/[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 960 - (show annotations) (download)
Wed Apr 20 01:25:05 2011 UTC (9 years, 3 months ago) by anssi
File size: 17624 byte(s)
service_harddrake: load new drivers or ask for reboot also if the driver is
switched due to a hardware change instead of an ldetect-lst change.
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 ask_with_timeout {
80 my ($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", $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!Driver "($old_driver)"!Driver "$new_driver"!g } '/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 graphic card '%s' is no more supported by the '%s' driver",
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 { $_, "$_.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 '%s' X.org driver",
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 if (!$reboot_needed && text2bool($cfg{HANDLE_KMS_BOOT_CONFIG})) {
264 if (-x "/sbin/display_driver_helper" && system("display_driver_helper", "--check-loaded") != 0) {
265 # incorrect driver is loaded, X.org can't start (e.g. proprietary driver loaded while free driver in use,
266 # or free driver loaded while vesa is configured).
267 $reboot_needed |= Xconfig::various::setup_kms();
268 } elsif (!$reboot_needed && -e "/dev/.late_kms") {
269 # initrd didn't load the KMS driver; non-fatal but ugly, fix it for next boot
270 unlink("/dev/.late_kms");
271 Xconfig::various::setup_kms();
272 }
273 }
274
275 my $is_globetrotter = -f '/usr/sbin/mdkmove';
276
277 my (%config, $wait);
278 my $in;
279 my $plymouth = -x '/bin/plymouth';
280
281 # For each hw, class, detect device, compare and offer to reconfigure if needed
282 foreach my $hw_class (@harddrake::data::tree) {
283 my ($Ident, $item, $configurator, $detector, $do_it) = @$hw_class{qw(class string configurator detector checked_on_boot)};
284 next if member($cfg{"DETECT_$Ident"}, qw(NO no));
285
286 $configurator ||= $hw_class->{configurator};
287
288 next unless $do_it ^ $invert_do_it;
289 # No detector ? (should never happen but who know ?)
290 ref($detector) eq 'CODE' or next;
291
292 my %ID = map {
293 my $i = $_;
294 my $id = defined $i->{device} ? $i->{device} : join(':', map { $i->{$_} } qw(vendor id subvendor subid));
295 $id => $i;
296 } eval { $detector->({}) };
297 $config{$Ident} = \%ID;
298 next if !$is_globetrotter && !$force && $first_run; # do not fsck on first run but if --force
299
300 my $oldconfig = $force ? {} : $previous_config->{$Ident};
301
302 my $msg;
303 my @was_removed = difference2([ keys %$oldconfig ], [ keys %ID ]);
304 if (@was_removed) {
305 $msg .= N("Some devices in the \"%s\" hardware class were removed:\n", $item) .
306 join('', map { N("- %s was removed\n", harddrake::data::custom_id($oldconfig->{$_}, $item)) } @was_removed) . "\n";
307 }
308 my @added = difference2([ keys %ID ], [ keys %$oldconfig ]);
309 $msg .= N("Some devices were added: %s\n", $item) if @added;
310 $msg .= N("- %s was added\n", harddrake::data::custom_id($ID{$_}, $item)) foreach @added;
311 log::explanations("removed $Ident: " . harddrake::data::custom_id($oldconfig->{$_}, $item)) foreach @was_removed;
312 log::explanations("added $Ident: " . harddrake::data::custom_id($ID{$_}, $item)) foreach @added;
313
314 if ($Ident eq 'FIREWIRE_CONTROLLER' && any { $_->{driver} eq 'ohci1394' } @ID{@added}) {
315 modules::load_and_configure($modules_conf, 'ohci1394');
316 $modules_conf->write;
317 }
318
319 @added || @was_removed or $cfg{"DETECT_$Ident"} ne 'force' and next;
320
321 next if $Ident eq 'MOUSE' && $kernel_major ne $previous_kernel_config{KERNEL} && $cfg{"DETECT_$Ident"} ne 'force';
322
323 my @configurator_pool = $configurator;
324
325 if ($Ident eq "AUDIO") {
326 # automatic sound slots configuration
327 rm_rf("/etc/asound.state") if -e "/etc/asound.state";
328 harddrake::sound::configure_sound_slots($modules_conf);
329 next;
330 } elsif ($Ident eq "ETHERNET") {
331 $modules_conf->remove_alias_regexp('^(wlan|eth)[0-9]*$');
332 modules::load_category($modules_conf, 'network/main|gigabit|usb|wireless|firewire|pcmcia');
333 require network::connection::ethernet;
334 network::connection::ethernet::configure_eth_aliases($modules_conf);
335 require network::rfswitch;
336 network::rfswitch::configure();
337 require network::shorewall;
338 network::shorewall::update_interfaces_list();
339 $modules_conf->write;
340 next;
341 } elsif (member($Ident, qw(ATA_STORAGE CARD_READER RAID_STORAGE SATA_STORAGE SCSI_CONTROLLER))) {
342 # set scsi_hostadapter in modprobe.conf:
343 modules::load_category($modules_conf, 'disk/' . {
344 ATA_STORAGE => 'ide',
345 SATA_STORAGE => 'sata',
346 SCSI_CONTROLLER => 'scsi',
347 RAID_STORAGE => 'hardware_raid',
348 CARD_READER => 'card_reader'
349 }->{$Ident});
350 $modules_conf->write;
351 next;
352 } elsif (member($Ident, qw(AGP DVB TV))) {
353 my @old_drivers = uniq(map { $_->{driver} } values %$oldconfig);
354 my @new_drivers = uniq(map { $_->{driver} } values %ID);
355 # load DVB & TV drivers (eg: for One), not for AGP (done by X):
356 modules::load_category($modules_conf, 'multimedia/' . lc($Ident)) if member($Ident, qw(DVB TV));
357 $modules_conf->remove_module(difference2(\@old_drivers, \@new_drivers));
358 # add agpgart and the like modules to modprobe.preload if needed:
359 $modules_conf->write;
360 foreach (difference2(\@new_drivers, \@old_drivers)) {
361 eval { modules::load($_) };
362 warn "warning: $@" if $@;
363 }
364 next;
365 } elsif ($Ident eq "BLUETOOTH") {
366 harddrake::autoconf::bluetooth(scalar keys %ID);
367 } elsif ($Ident eq "PCMCIA_CONTROLLER") {
368 harddrake::autoconf::pcmcia(keys %ID ? first(values(%ID))->{driver} : '');
369 } elsif ($Ident eq "USB_CONTROLLER") {
370 # nearly useless (only mkinitrd uses it):
371 modules::load_category($modules_conf, 'bus/usb');
372 $modules_conf->write;
373 } elsif ($Ident eq "VIDEO") {
374 # explicitely NOT read the existing config (eg: new profile with globetrotter)
375 harddrake::autoconf::xconf($modules_conf, {}, member($cfg{SETUP_FB}, qw(NO no)), $cfg{RESOLUTION_WANTED});
376 $reboot_needed |= after_x_driver_switch();
377 $do_udev_settle = 1;
378 next;
379 } elsif ($Ident eq "MOUSE") {
380 harddrake::autoconf::mouse_conf($modules_conf);
381 next;
382 } elsif ($Ident eq "CPU") {
383 harddrake::autoconf::cpufreq();
384 } elsif ($Ident eq "FLOPPY") {
385 harddrake::autoconf::floppy();
386 }
387
388 next if $is_globetrotter && !$hw_class->{automatic};
389 next unless $configurator_pool[0];
390 if (ref($configurator) ne 'CODE' && !-x first(split /\s+/, $configurator_pool[0])) {
391 log::explanations(qw(skip $Ident configuration since "$configurator" is not executable));
392 next;
393 }
394 my ($no, $res);
395 $hw_class->{automatic} ||= ref($configurator) eq 'CODE';
396
397 if (!$hw_class->{automatic}) {
398 ($res, $no) = ask_with_timeout(N("Hardware changes in \"%s\" class (%s seconds to answer)", $Ident, $timeout),
399 $msg . N("Do you want to run the appropriate config tool?"), $timeout, $plymouth);
400 } else {
401 $res = 1;
402 }
403 if (ref($configurator) eq 'CODE') {
404 eval { $configurator->() };
405 log::explanations(qw(cannot run "$configurator": $@)) if $@;
406 } elsif (!$no && $res) {
407 foreach my $program (@configurator_pool) {
408 if (fork()) {
409 wait();
410 } else {
411 log::explanations(qq(run "$program"));
412 exec("$program 2>/dev/null") or do {
413 log::explanations(qq(cannot run "$program"));
414 require POSIX;
415 POSIX::_exit();
416 };
417 }
418 }
419 }
420 if (!$hw_class->{automatic}) {
421 require interactive;
422 undef $wait;
423 $in ||= interactive->vnew;
424 $wait = $in->wait_message(N("Please wait"), N("Hardware probing in progress"));
425 }
426
427 }
428
429 # output new hw config
430 log::explanations("created file $last_boot_config");
431 Storable::store(\%config, $last_boot_config);
432
433 # Handle $reboot_needed from earlier:
434 my ($reply, $timedout);
435 # Don't do autoreboot if X was somehow already started (not normally the case).
436 if ($reboot_needed && ! -e "/tmp/.X11-unix/X0") {
437 ($reply, $timedout) = ask_with_timeout(N("Display driver setup"), N("The system has to be rebooted due to a display driver change.") . "\n\n"
438 . N("Press Cancel within %d seconds to abort.", 30), 30, $plymouth);
439 if ($reply || $timedout) {
440 exec("/sbin/reboot");
441 }
442 }
443
444 system("udevadm", "settle", "--timeout=10") if $do_udev_settle;
445
446 $in->exit(0) if $in;

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.28