/[soft]/drakx/trunk/perl-install/standalone/service_harddrake
ViewVC logotype

Contents of /drakx/trunk/perl-install/standalone/service_harddrake

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3178 - (show annotations) (download)
Fri Mar 2 18:48:09 2012 UTC (11 years, 9 months ago) by anssi
File size: 18905 byte(s)
service_harddrake: recognize XZ compressed modules properly (mga#4767)
1 #!/usr/bin/perl
2
3 use lib qw(/usr/lib/libDrakX);
4
5 # prevent firing up drakbug (doesn't work w/o X11):
6 BEGIN { $ENV{DISABLE_DRAKBUG} = 1 }
7
8 use strict;
9 use diagnostics;
10
11 # fix translating reasons for 2nd stage warning
12 use lang;
13 BEGIN {
14 my $locale = lang::read($>);
15 lang::set($locale);
16 }
17
18 use standalone; #- warning, standalone must be loaded very first, for 'explanations'
19 use c;
20 use common;
21 use interactive;
22 use detect_devices;
23 use harddrake::data;
24 use harddrake::autoconf;
25 use harddrake::sound;
26 use Xconfig::card;
27 use Xconfig::various;
28 use modules;
29 use Storable qw(store retrieve);
30
31
32 my $force = member('--force', @ARGV);
33 my $reboot_needed;
34 my $do_udev_settle;
35
36 my $invert_do_it = $ARGV[0] eq 'X11' ? 1 : 0;
37 my ($hw_sysconfdir, $timeout) = ("/etc/sysconfig/harddrake2", $invert_do_it ? 600 : 25);
38 my $last_boot_config = "$hw_sysconfdir/previous_hw";
39
40 $last_boot_config .= '_X11' if $invert_do_it;
41
42 # first run ? if not read old hw config
43 my $previous_config;
44 if (-f $last_boot_config && -s $last_boot_config) {
45 eval { $previous_config = Storable::retrieve($last_boot_config) };
46 log::explanations("resetting previous hardware file ($@)") if $@;
47 }
48 $previous_config ||= {};
49 $previous_config = $$previous_config if ref($previous_config) !~ /HASH/;
50 my $first_run = is_empty_hash_ref($previous_config);
51
52 my $modules_conf = modules::any_conf->read;
53
54 my $isLaptop = detect_devices::isLaptop();
55 my $curr_kernel = c::kernel_version();
56 my ($kernel_major) = $curr_kernel =~ /^(\d+\.\d+)/;
57
58 my %previous_kernel_config = getVarsFromSh("$hw_sysconfdir/kernel");
59 my %previous_xorg_config = getVarsFromSh("$hw_sysconfdir/xorg");
60 setVarsInSh("$hw_sysconfdir/kernel", { KERNEL => $kernel_major, IS_LAPTOP => bool2text($isLaptop) });
61 my %cfg = getVarsFromSh("$hw_sysconfdir/service.conf");
62
63 # default to 'yes' on upgrade:
64 $cfg{AUTORECONFIGURE_RIGHT_XORG_DRIVER} = 'yes' if !exists $cfg{AUTORECONFIGURE_RIGHT_XORG_DRIVER};
65 $cfg{HANDLE_KMS_BOOT_CONFIG} = 'yes' if !exists $cfg{HANDLE_KMS_BOOT_CONFIG};
66
67 # autoreconfigure laptop-dependent services when switching from laptop to desktop, and vice versa
68 if (!exists $previous_kernel_config{IS_LAPTOP} || $force || $isLaptop != text2bool($previous_kernel_config{IS_LAPTOP})) {
69 log::explanations("Autoconfiguring laptop tools since we switched between laptop and desktop systems");
70 harddrake::autoconf::laptop($isLaptop);
71 }
72
73 my $known_kernels = "$hw_sysconfdir/kernels";
74 if (!member($curr_kernel, chomp_(cat_($known_kernels)))) {
75 harddrake::autoconf::fix_aliases($modules_conf) if !$first_run;
76 append_to_file($known_kernels, "$curr_kernel\n");
77 }
78
79 sub dialog_with_timeout {
80 my ($type, $title, $msg, $timeout, $plymouth) = @_;
81 my ($pid, $res, $timed_out);
82
83 $SIG{ALRM} = sub { $timed_out = 1; kill 15, $pid };
84 unless ($pid = fork()) {
85 $plymouth and system('plymouth', 'hide-splash');
86 exec("/usr/share/harddrake/confirm", $type, $title, $msg);
87 }
88 alarm($timeout);
89 wait();
90 $res = $?;
91 alarm(0);
92 return $res, $timed_out;
93 }
94
95 sub get_xorg_driver() {
96 my $x = Xconfig::xfree->read;
97 if ($x) {
98 my ($dev_section) = grep { $_->{name} eq 'Device' } @{$x->{raw}};
99 $dev_section && $dev_section->{l}{Driver}{val};
100 }
101 }
102
103 sub schedule_warn_about_switch {
104 my ($reason) = @_;
105 output('/var/run/harddrake-notify-x11-free-driver-switch', $reason);
106 }
107
108 my $lib = arch() =~ /x86_64/ ? "lib64" : "lib";
109
110 sub find_xorg_driver {
111 my ($new_driver) = @_;
112 # nvidia driver has special place:
113 -e "/usr/$lib/xorg/modules/drivers/${new_driver}_drv.so"
114 || -e "/usr/$lib/xorg/extra-modules/${new_driver}_drv.so";
115 }
116
117 sub after_x_driver_switch {
118 # If a wrong driver is loaded, ask for a reboot.
119 my $reboot_needed = -x "/sbin/display_driver_helper" && system("/sbin/display_driver_helper", "--check-loaded") != 0;
120 if (!$reboot_needed) {
121 # Load any new drivers.
122 system("udevadm", "trigger", "--subsystem-match=pci", "--attr-match=class=0x03*");
123 }
124 $reboot_needed;
125 }
126
127 sub switch_x_driver {
128 my ($old_driver, $new_driver, $reason) = @_;
129 if (!find_xorg_driver($new_driver)) {
130 log::explanations("would switch X.org driver from '$old_driver' to '$new_driver' ($reason); but new driver is not installed");
131 return;
132 }
133 # This should use calls to Xconfig instead of substitution. However, currently
134 # Xconfig probably makes too intrusive changes to xorg.conf when switching the driver.
135 cp_af('/etc/X11/xorg.conf', "/etc/X11/xorg.conf.mga$^T");
136 substInFile { s!^(\s*Driver\s+)"$old_driver"!$1"$new_driver"!i } '/etc/X11/xorg.conf';
137 log::explanations("switch X.org driver from '$old_driver' to '$new_driver' ($reason)");
138 Xconfig::card::libgl_config_and_more({ Driver => $new_driver });
139 Xconfig::various::setup_kms();
140
141 after_x_driver_switch(); # returns 1 if reboot is needed
142 }
143
144 sub should_reconfigure_x_driver {
145 my ($card_data, $device, $current_driver) = @_;
146 my $reason;
147 my $reconfigure;
148 my $new_key = $card_data->{Driver} . $card_data->{Driver2};
149 setVarsInSh("$hw_sysconfdir/xorg", { XORG_DRV => $new_key });
150 # auto reconfigure x11 only on first time default driver have changed:
151 if ($previous_xorg_config{XORG_DRV} ne $new_key) {
152 if (!member($current_driver, $card_data->{Driver}, $card_data->{Driver2}, 'fbdev', 'vesa')) {
153 $reason = N("The graphics card '%s' is no longer supported by driver '%s'",
154 $device->{description}, $current_driver);
155 $reconfigure = 1;
156 }
157 } elsif ((stat('/etc/X11/xorg.conf'))[9] < (stat('/etc/product.id'))[9]) {
158 # when switching to a new release (product.id is newer than xorg.conf),
159 # regenerate xorg.conf even if the driver used is vesa or fbdev, this
160 # way we handle switches like "no driver for the card in older releases
161 # but good driver in new release", see bug #53753
162 if (!member($current_driver, $card_data->{Driver}, $card_data->{Driver2})) {
163 $reason = N("New release, reconfiguring X for %s", $device->{description});
164 $reconfigure = 1;
165 }
166 }
167
168 ($reconfigure, $reason);
169 }
170
171 my @cards = (
172 {
173 ldetect_driver_regexp => 'Card:NVIDIA',
174 xorg_driver_regexp => 'nv.+',
175 module_names => [ qw(NVdriver nvidia.o nvidia.ko nvidia71xx.ko nvidia96xx.ko nvidia97xx.ko nvidia173.ko nvidia-current.ko) ]
176 },
177 {
178 ldetect_driver_regexp => 'Card:ATI Radeon',
179 xorg_driver_regexp => 'fglrx',
180 module_names => [ qw(fglrx.ko fglrx-hd2000.ko) ]
181 }
182 );
183
184
185 my @devices;
186 @devices = grep { $_->{driver} =~ /^Card:/ } detect_devices::probeall()
187 if -f '/etc/X11/xorg.conf';
188
189 # do not auto reconfigure if more than one graphic card:
190 $cfg{AUTORECONFIGURE_RIGHT_XORG_DRIVER} = 'no' if scalar(@devices) > 1;
191
192 foreach my $device (@devices) {
193 next if !text2bool($cfg{AUTORECONFIGURE_RIGHT_XORG_DRIVER});
194
195 my $id = $device->{driver} =~ /Card:(.*)/ && $1;
196 my $card_data = Xconfig::card::readCardsDB("/usr/share/ldetect-lst/Cards+")->{$id};
197 my $current_driver = get_xorg_driver();
198
199 # nvidia proprietary driver in ldetect-lst can be 'nvidia173', 'nvidia-current', ...
200 # but really is just 'nvidia' in xorg.conf:
201 $card_data->{Driver2} =~ s/(nvidia).*/$1/;
202
203 # auto reconfigure x11 only on first time default driver have changed:
204 my ($should_reconfigure, $reason) = should_reconfigure_x_driver($card_data, $device, $current_driver);
205 if ($should_reconfigure) {
206 if (-e "/tmp/.X11-unix/X0") {
207 # We are too late, X server is already running.
208 # It was probably speedboot, disable it for next boot.
209 substInFile { s!^$curr_kernel .*\n!! } "/var/lib/speedboot/status" if -e "/var/lib/speedboot/status";
210 # Restore state as we were not able to switch the driver yet.
211 setVarsInSh("$hw_sysconfdir/xorg", { XORG_DRV => $previous_xorg_config{XORG_DRV} });
212 } else {
213 $reboot_needed |= switch_x_driver($current_driver, $card_data->{Driver}, $reason);
214 $do_udev_settle = 1;
215 schedule_warn_about_switch($reason) if any { $current_driver =~ $_->{xorg_driver_regexp} } @cards;
216 # Update $current_driver with the new one
217 $current_driver = $card_data->{Driver};
218 }
219 }
220
221 # nv->nouveau or non_kms_nouveau->kms_nouveau can't have "Disable dri"!
222 if ($current_driver eq "nouveau") {
223 my $raw_x = Xconfig::xfree->read;
224 if ($raw_x) {
225 if (member("dri", $raw_x->get_disabled_modules)) {
226 $raw_x->remove_disable_module("dri");
227 $raw_x->write;
228 }
229 }
230 }
231 }
232
233
234 foreach my $card (@cards) {
235 my $device = find { $_->{driver} =~ /$card->{ldetect_driver_regexp}/ } @devices;
236 next if !$device;
237
238 if (find { -e join('', "/lib/modules/", c::kernel_version(), $_) }
239 map { ("/dkms/$_", "/dkms-binary/$_", "/kernel/$_") } map { "/drivers/$_" } map { ("extra/$_", "video/$_", "char/$_", "char/drm/$_") } map { $_, "$_.xz", "$_.gz" } @{$card->{module_names}}) {
240
241 # do not automatically switch from nv to nvidia (in order to handle
242 # cases where nvidia module crashes the system):
243 #
244 # substInFile {
245 # log::explanations("switch XFree86 driver from nv to nvidia") if /Driver "nv"/;
246 # s!Driver "nv.*"!Driver "nvidia"!g;
247 # s!#*( Load.*glx)!\1!g;
248 # } $_ foreach "/etc/X11/XF86Config-4", "/etc/X11/XF86Config";
249 } else {
250 my @cards = Xconfig::card::probe();
251 my $driver = $cards[0]{Driver};
252 my $old_driver = cat_('/etc/X11/xorg.conf') =~ /Driver "($card->{xorg_driver_regexp})"/ && $1;
253 if ($old_driver) {
254 my $reason = N("The proprietary kernel driver was not found for X.org driver '%s'",
255 $old_driver);
256 $reboot_needed |= switch_x_driver($card->{xorg_driver_regexp}, $driver, $reason);
257 $do_udev_settle = 1;
258 schedule_warn_about_switch($reason);
259 }
260 }
261 }
262
263 my $is_globetrotter = -f '/usr/sbin/mdkmove';
264
265 my (%config, $wait);
266 my $in;
267 my $plymouth = -x '/bin/plymouth';
268
269 # For each hw, class, detect device, compare and offer to reconfigure if needed
270 foreach my $hw_class (@harddrake::data::tree) {
271 my ($Ident, $item, $configurator, $detector, $do_it) = @$hw_class{qw(class string configurator detector checked_on_boot)};
272 next if member($cfg{"DETECT_$Ident"}, qw(NO no));
273
274 $configurator ||= $hw_class->{configurator};
275
276 next unless $do_it ^ $invert_do_it;
277 # No detector ? (should never happen but who know ?)
278 ref($detector) eq 'CODE' or next;
279
280 my %ID = map {
281 my $i = $_;
282 my $id = defined $i->{device} ? $i->{device} : join(':', map { $i->{$_} } qw(vendor id subvendor subid));
283 $id => $i;
284 } eval { $detector->({}) };
285 $config{$Ident} = \%ID;
286 next if !$is_globetrotter && !$force && $first_run; # do not fsck on first run but if --force
287
288 my $oldconfig = $force ? {} : $previous_config->{$Ident};
289
290 my $msg;
291 my @was_removed = difference2([ keys %$oldconfig ], [ keys %ID ]);
292 if (@was_removed) {
293 $msg .= N("Some devices in the \"%s\" hardware class were removed:\n", $item) .
294 join('', map { N("- %s was removed\n", harddrake::data::custom_id($oldconfig->{$_}, $item)) } @was_removed) . "\n";
295 }
296 my @added = difference2([ keys %ID ], [ keys %$oldconfig ]);
297 $msg .= N("Some devices were added: %s\n", $item) if @added;
298 $msg .= N("- %s was added\n", harddrake::data::custom_id($ID{$_}, $item)) foreach @added;
299 log::explanations("removed $Ident: " . harddrake::data::custom_id($oldconfig->{$_}, $item)) foreach @was_removed;
300 log::explanations("added $Ident: " . harddrake::data::custom_id($ID{$_}, $item)) foreach @added;
301
302 if ($Ident eq 'FIREWIRE_CONTROLLER' && any { $_->{driver} eq 'ohci1394' } @ID{@added}) {
303 modules::load_and_configure($modules_conf, 'ohci1394');
304 $modules_conf->write;
305 }
306
307 @added || @was_removed or $cfg{"DETECT_$Ident"} ne 'force' and next;
308
309 next if $Ident eq 'MOUSE' && $kernel_major ne $previous_kernel_config{KERNEL} && $cfg{"DETECT_$Ident"} ne 'force';
310
311 my @configurator_pool = $configurator;
312
313 if ($Ident eq "AUDIO") {
314 # automatic sound slots configuration
315 rm_rf("/etc/asound.state") if -e "/etc/asound.state";
316 harddrake::sound::configure_sound_slots($modules_conf);
317 next;
318 } elsif ($Ident eq "ETHERNET") {
319 $modules_conf->remove_alias_regexp('^(wlan|eth)[0-9]*$');
320 modules::load_category($modules_conf, 'network/main|gigabit|usb|wireless|firewire|pcmcia');
321 require network::connection::ethernet;
322 network::connection::ethernet::configure_eth_aliases($modules_conf);
323 require network::rfswitch;
324 network::rfswitch::configure();
325 require network::shorewall;
326 network::shorewall::update_interfaces_list();
327 $modules_conf->write;
328 next;
329 } elsif (member($Ident, qw(ATA_STORAGE CARD_READER RAID_STORAGE SATA_STORAGE SCSI_CONTROLLER))) {
330 # set scsi_hostadapter in modprobe.conf:
331 modules::load_category($modules_conf, 'disk/' . {
332 ATA_STORAGE => 'ide',
333 SATA_STORAGE => 'sata',
334 SCSI_CONTROLLER => 'scsi',
335 RAID_STORAGE => 'hardware_raid',
336 CARD_READER => 'card_reader'
337 }->{$Ident});
338 $modules_conf->write;
339 next;
340 } elsif (member($Ident, qw(AGP DVB TV))) {
341 my @old_drivers = uniq(map { $_->{driver} } values %$oldconfig);
342 my @new_drivers = uniq(map { $_->{driver} } values %ID);
343 # load DVB & TV drivers (eg: for One), not for AGP (done by X):
344 modules::load_category($modules_conf, 'multimedia/' . lc($Ident)) if member($Ident, qw(DVB TV));
345 $modules_conf->remove_module(difference2(\@old_drivers, \@new_drivers));
346 # add agpgart and the like modules to modprobe.preload if needed:
347 $modules_conf->write;
348 foreach (difference2(\@new_drivers, \@old_drivers)) {
349 eval { modules::load($_) };
350 warn "warning: $@" if $@;
351 }
352 next;
353 } elsif ($Ident eq "BLUETOOTH") {
354 harddrake::autoconf::bluetooth(scalar keys %ID);
355 } elsif ($Ident eq "PCMCIA_CONTROLLER") {
356 harddrake::autoconf::pcmcia(keys %ID ? first(values(%ID))->{driver} : '');
357 } elsif ($Ident eq "USB_CONTROLLER") {
358 # nearly useless (only mkinitrd uses it):
359 modules::load_category($modules_conf, 'bus/usb');
360 $modules_conf->write;
361 } elsif ($Ident eq "VIDEO") {
362 # explicitely NOT read the existing config (eg: new profile with globetrotter)
363 harddrake::autoconf::xconf($modules_conf, {}, member($cfg{SETUP_FB}, qw(NO no)), $cfg{RESOLUTION_WANTED});
364 $reboot_needed |= after_x_driver_switch();
365 $do_udev_settle = 1;
366 next;
367 } elsif ($Ident eq "MOUSE") {
368 harddrake::autoconf::mouse_conf($modules_conf);
369 next;
370 } elsif ($Ident eq "CPU") {
371 harddrake::autoconf::cpufreq();
372 } elsif ($Ident eq "FLOPPY") {
373 harddrake::autoconf::floppy();
374 }
375
376 next if $is_globetrotter && !$hw_class->{automatic};
377 next unless $configurator_pool[0];
378 if (ref($configurator) ne 'CODE' && !-x first(split /\s+/, $configurator_pool[0])) {
379 log::explanations(qw(skip $Ident configuration since "$configurator" is not executable));
380 next;
381 }
382 my ($no, $res);
383 $hw_class->{automatic} ||= ref($configurator) eq 'CODE';
384
385 if (!$hw_class->{automatic}) {
386 ($res, $no) = dialog_with_timeout("yesorno", N("Hardware changes in \"%s\" class (%s seconds to answer)", $Ident, $timeout),
387 $msg . N("Do you want to run the appropriate config tool?"), $timeout, $plymouth);
388 } else {
389 $res = 1;
390 }
391 if (ref($configurator) eq 'CODE') {
392 eval { $configurator->() };
393 log::explanations(qw(cannot run "$configurator": $@)) if $@;
394 } elsif (!$no && $res) {
395 foreach my $program (@configurator_pool) {
396 if (fork()) {
397 wait();
398 } else {
399 log::explanations(qq(run "$program"));
400 exec("$program 2>/dev/null") or do {
401 log::explanations(qq(cannot run "$program"));
402 require POSIX;
403 POSIX::_exit();
404 };
405 }
406 }
407 }
408 if (!$hw_class->{automatic}) {
409 require interactive;
410 undef $wait;
411 $in ||= interactive->vnew;
412 $wait = $in->wait_message(N("Please wait"), N("Hardware probing in progress"));
413 }
414
415 }
416
417 # output new hw config
418 log::explanations("created file $last_boot_config");
419 Storable::store(\%config, $last_boot_config);
420
421 if (!$reboot_needed && text2bool($cfg{HANDLE_KMS_BOOT_CONFIG})) {
422 if (-x "/sbin/display_driver_helper" && system("display_driver_helper", "--check-loaded") != 0) {
423 # incorrect driver is loaded, X.org can't start (e.g. proprietary driver loaded while free driver in use,
424 # or free driver loaded while vesa is configured).
425 my $kms_changed = Xconfig::various::setup_kms();
426 $reboot_needed |= $kms_changed;
427 if (!$reboot_needed) {
428 my $kms_allowed = system("display_driver_helper", "--is-kms-allowed") == 0;
429 if (!$kms_allowed && cat_("/proc/cmdline") !~ /\bnokmsboot\b/) {
430 # Wrong driver loaded and boot parameters incorrect, but fixing the
431 # bootloader configuration failed.
432 # Possibly a direct boot from another bootloader.
433 dialog_with_timeout("warn", N("Display driver issue"),
434 N("The display driver currently configured requires you to use the 'nokmsboot' boot option to prevent the KMS driver of the kernel from being loaded in the boot process. Startup of the X server may now fail as that option was not specified."),
435 60, $plymouth);
436 } else {
437 # Wrong driver loaded even while boot parameters were correct.
438 dialog_with_timeout("warn", N("Display driver issue"),
439 N("Detected a loaded display driver kernel module which conflicts with the driver the X server is configured to use. Startup of the X server may now fail."),
440 60, $plymouth);
441 }
442 }
443 } elsif (-e "/dev/.late_kms") {
444 # initrd didn't load the KMS driver; non-fatal but ugly, fix it for next boot
445 unlink("/dev/.late_kms");
446 Xconfig::various::setup_kms();
447 }
448 }
449
450 # Handle $reboot_needed from earlier:
451 my ($reply, $timedout);
452 # Don't do autoreboot if X was somehow already started (not normally the case).
453 if ($reboot_needed && ! -e "/tmp/.X11-unix/X0") {
454 ($reply, $timedout) = dialog_with_timeout("okcancel", N("Display driver setup"), N("The system has to be rebooted due to a display driver change.") . "\n\n"
455 . N("Press Cancel within %d seconds to abort.", 30), 30, $plymouth);
456 if ($reply || $timedout) {
457 exec("/sbin/reboot");
458 }
459 }
460
461 system("udevadm", "settle", "--timeout=10") if $do_udev_settle;
462
463 $in->exit(0) if $in;

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.28