summaryrefslogtreecommitdiffstats
path: root/perl-install/install/any.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/install/any.pm')
-rw-r--r--perl-install/install/any.pm370
1 files changed, 271 insertions, 99 deletions
diff --git a/perl-install/install/any.pm b/perl-install/install/any.pm
index fe05557f5..4ea2ce45d 100644
--- a/perl-install/install/any.pm
+++ b/perl-install/install/any.pm
@@ -1,4 +1,4 @@
-package install::any; # $Id: any.pm 259898 2009-09-03 14:05:46Z tv $
+package install::any;
use strict;
@@ -23,8 +23,24 @@ use lang;
use any;
use log;
+=head1 SYNOPSYS
+
+Misc installer specific functions
+
+=head1 Functions
+
+=over
+
+=cut
+
our @advertising_images;
+=item drakx_version($o)
+
+Returns DrakX version as stored in C<install/stage2/VERSION> file
+
+=cut
+
sub drakx_version {
my ($o) = @_;
@@ -39,11 +55,23 @@ sub dont_run_directly_stage2() {
readlink("/usr/bin/runinstall2") eq "runinstall2.sh";
}
+=item is_network_install($o)
+
+Is it a network install?
+
+=cut
+
sub is_network_install {
my ($o) = @_;
member($o->{method}, qw(ftp http nfs));
}
+=item spawnShell()
+
+Starts a shell on tty2
+
+=cut
+
sub spawnShell() {
return if $::local_install || $::testing;
@@ -84,6 +112,12 @@ cant_spawn:
c::_exit(1);
}
+=item getAvailableSpace($o)
+
+Returns available space
+
+=cut
+
sub getAvailableSpace {
my ($o) = @_;
fs::any::getAvailableSpace($o->{fstab});
@@ -101,8 +135,29 @@ sub preConfigureTimezone {
my $utc = every { !isFat_or_NTFS($_) } @{$o->{fstab}};
my $ntp = timezone::ntp_server();
add2hash_($o->{timezone}, { UTC => $utc, ntp => $ntp });
+
+ #- Make the timezone available to urpm::mirrors.
+ write_installer_timezone($o->{timezone});
+}
+
+=item write_installer_timezone($timezone)
+
+Writes a minimal version of $timezone to /etc/sysconfig/clock for use by urpm::mirrors
+
+=cut
+
+sub write_installer_timezone {
+ my ($timezone) = @_;
+ mkdir_p('/etc/sysconfig/');
+ setVarsInSh('/etc/sysconfig/clock', { ZONE => $timezone->{timezone} });
}
+=item ask_suppl_media_method($o)
+
+Enables to add supplementary media
+
+=cut
+
sub ask_suppl_media_method {
my ($o) = @_;
our $suppl_already_asked;
@@ -119,14 +174,14 @@ Do you have a supplementary installation medium to configure?",
my %l = my @l = (
'' => N("None"),
- 'cdrom' => N("CD-ROM"),
'http' => N("Network (HTTP)"),
'ftp' => N("Network (FTP)"),
'nfs' => N("Network (NFS)"),
);
- $o->ask_from(
- '', $msg,
+ $o->ask_from_({ messages => $msg,
+ interactive_help_id => 'add_supplemental_media',
+ },
[ {
val => \my $suppl,
list => [ map { $_->[0] } group_by2(@l) ],
@@ -139,8 +194,13 @@ Do you have a supplementary installation medium to configure?",
$suppl;
}
-#- if the supplementary media is networked, but not the main one, network
-#- support must be installed and network started.
+=item prep_net_suppl_media($o)
+
+If the supplementary media is networked, but not the main one, network
+support must be installed and network started.
+
+=cut
+
sub prep_net_suppl_media {
my ($o) = @_;
@@ -148,13 +208,13 @@ sub prep_net_suppl_media {
return if our $net_suppl_media_configured && network::tools::has_network_connection();
$net_suppl_media_configured = 1;
- # needed so that one can install basesystem before adding suppl network media:
+ # needed so that one can install basesystem-minimal before adding suppl network media:
install::media::update_media($o->{packages});
require urpm::media;
urpm::media::configure($o->{packages});
- #- install basesystem now
- $o->do_pkgs->ensure_is_installed('basesystem', undef, 1);
+ #- install basesystem-minimal now
+ $o->do_pkgs->ensure_is_installed('basesystem-minimal', undef, 1);
# in case of no network install:
$o->{net} ||= {};
@@ -165,69 +225,14 @@ sub prep_net_suppl_media {
sleep(3);
}
-sub ask_url {
- my ($in, $o_url) = @_;
-
- my $url = $o_url;
- $in->ask_from_({ messages => N("URL of the mirror?"), focus_first => 1 }, [
- { val => \$url,
- validate => sub {
- if ($url =~ m!^(http|ftp)://!) {
- 1;
- } else {
- $in->ask_warn('', N("URL must start with ftp:// or http://"));
- 0;
- }
- } } ]) && $url;
-}
-sub ask_mirror {
- my ($o, $type, $o_url) = @_;
-
- require mirror;
-
- my $mirrors = eval {
- my $_w = $o->wait_message('', N("Contacting %s web site to get the list of available mirrors...", N("Mageia")));
- mirror::list($o->{product_id}, $type);
- };
- my $err = $@;
- if (!$mirrors) {
- $o->ask_warn('', N("Failed contacting %s web site to get the list of available mirrors", N("Mageia")) . "\n$err");
- return ask_url($o, $o_url);
- }
-
- my $give_url = { country => '-', host => 'URL' };
-
- my $mirror = $o_url ? (find { $_->{url} eq $o_url } @$mirrors) || $give_url
- #- use current time zone to select best mirror
- : mirror::nearest($o->{timezone}{timezone}, $mirrors);
-
- $o->ask_from_({ messages => N("Choose a mirror from which to get the packages"),
- cancel => N("Cancel"),
- }, [ { separator => '|',
- format => \&mirror::mirror2text,
- list => [ @$mirrors, $give_url ],
- val => \$mirror,
- },
- ]) or return;
-
- my $url;
- if ($mirror eq $give_url) {
- $url = ask_url($o, $o_url) or goto &ask_mirror;
- } else {
- $url = $mirror->{url};
- }
- $url =~ s!/main/?$!!;
- log::l("chosen mirror: $url");
- $url;
-}
-
sub ask_suppl_media_url {
my ($o, $method, $o_url) = @_;
- if ($method eq 'ftp' || $method eq 'http') {
- install::any::ask_mirror($o, 'distrib', $o_url);
- } elsif ($method eq 'cdrom') {
- 'cdrom://';
+ if (member($method, qw(ftp http))) {
+ preConfigureTimezone($o);
+ any::ask_mirror_and_downloader($o, $o->{options}, 'downloader_only');
+ $o->{packages}{options}{downloader} = $o->{options}{downloader};
+ any::ask_mirror($o, 'distrib', $o_url);
} elsif ($method eq 'nfs') {
my ($host, $dir) = $o_url ? $o_url =~ m!nfs://(.*?)(/.*)! : ();
$o->ask_from_(
@@ -249,6 +254,14 @@ sub ask_suppl_media_url {
"nfs://$host$dir";
} else { internal_error("bad method $method") }
}
+
+
+=item selectSupplMedia($o)
+
+Offers to add a supplementary media. If yes, ask which mirror to use, ...
+
+=cut
+
sub selectSupplMedia {
my ($o) = @_;
my $url;
@@ -257,7 +270,7 @@ sub selectSupplMedia {
my $method = ask_suppl_media_method($o) or return;
#- configure network if needed
- if (!scalar keys %{$o->{net}{ifcfg}} && $method !~ /^(?:cdrom|disk)/ && !$::local_install) {
+ if (!scalar keys %{$o->{net}{ifcfg}} && $method !~ /^(?:disk)/ && !$::local_install) {
prep_net_suppl_media($o);
}
@@ -303,6 +316,15 @@ sub selectSupplMedia {
goto ask_url;
}
+=item load_rate_files($o)
+
+Loads the package rates file (C<rpmsrate>) as well as the C<compssUsers.pl>
+file which contains the package groups GUI.
+
+Both files came from the C<meta-task> package.
+
+=cut
+
sub load_rate_files {
my ($o) = @_;
#- must be done after getProvides
@@ -322,10 +344,34 @@ sub _tainted_medium() { N("Tainted Release") }
sub _nonfree_medium() { N("Nonfree Release") }
# FIXME: move me in ../any.pm or in harddrake::*, might be needed by rpmdrake/harddrake:
-sub is_firmware_needed {
+sub is_firmware_needed_ {
my ($o) = @_;
+ require list_firmwares;
+ my @l = map { $_->{driver} } detect_devices::probeall();
+ my @need = intersection(\@l, \@list_firmwares::modules_with_nonfree_firmware);
+ log::l("the following driver(s) need nonfree firmware(s): " . join(', ', @need)) if @need;
+
require pkgs;
- pkgs::detect_graphical_drivers($o->do_pkgs);
+ my @xpkgs = pkgs::detect_graphical_drivers($o->do_pkgs, undef, 'firmware-only');
+ log::l("the following nonfree firmware(s) are needed for X.org: " . join(', ', @xpkgs)) if @xpkgs;
+
+ my $need_microcode = detect_devices::hasCPUMicrocode();
+ log::l("nonfree firmware is needed for the CPU (microcode)") if $need_microcode;
+
+ if_(@need, 'kernel-firmware-nonfree'), @xpkgs, if_($need_microcode, 'microcode');
+}
+
+=item is_firmware_needed($o)
+
+Is a firmware needed by some HW?
+
+=cut
+
+sub is_firmware_needed {
+ my ($o) = @_;
+ state $res;
+ $res = is_firmware_needed_($o) if !defined $res;
+ $res;
}
sub msg_if_firmware_needed {
@@ -338,6 +384,39 @@ sub msg_if_firmware_needed {
);
}
+=item enable_nonfree_media($medium)
+
+Enable a disabled Nonfree medium.
+
+=cut
+
+sub enable_nonfree_media {
+ my ($medium) = @_;
+ return if $medium->{name} !~ /Nonfree/ || $medium->{name} =~ /32bit/ || !$medium->{ignore};
+ log::l("preselecting $medium->{name}");
+ $medium->{temp_enabled} = 1;
+}
+
+=item enable_core_32bit_media($medium)
+
+Enable a disabled Core 32bit medium.
+
+=cut
+
+sub enable_core_32bit_media {
+ my ($medium) = @_;
+ return if $medium->{name} !~ /Core/ || $medium->{name} !~ /32bit/ || !$medium->{ignore};
+ log::l("preselecting $medium->{name}");
+ $medium->{temp_enabled} = 1;
+}
+
+=item media_screen($o)
+
+Lists available media with their status (enabled/disabled).
+Suggests to enable Nonfree media if needed.
+
+=cut
+
sub media_screen {
my ($o) = @_;
@@ -346,24 +425,26 @@ sub media_screen {
# - nice info
# - ignore already failed media (such as 32bit media on NFS)
# - detect if non-free/tainted were selected previously / are now needed
- # rpm -qa |grep tainted/non-free + check for kmod with firmwares
+ # rpm -qa |grep tainted/non-free
# - use red color in that case (gtk+ version? interactive::gtk version?)
# - present media as trees (eg 3 main branches (core/nonfree/tainted and sub medium below (release/updates/...)
# - enable to add media from the media screen
- # - use keywords (backports,testing,testing,sources) to blacklist
# - introduce 'mandatory' keyword for guessing media that can *not* be disabled
my %descriptions = (
'Core Release' => N("\"%s\" contains the various pieces of the systems and its applications", _core_medium()),
- 'Nonfree Release' => N("\"%s\" contains non free software.\n", _nonfree_medium()) .
+ 'Nonfree Release' => N("\"%s\" contains non free software.\n", _nonfree_medium()) . " " .
N("It also contains firmwares needed for certain devices to operate (eg: some ATI/AMD graphic cards, some network cards, some RAID cards, ...)"),
- 'Tainted Release' => N("\"%s\" contains software that can not be distributed in every country due to software patents.", _tainted_medium()) .
+ 'Tainted Release' => N("\"%s\" contains software that can not be distributed in every country due to software patents.", _tainted_medium()) . " " .
N("It also contains software from \"%s\" rebuild with additional capabilities.", _core_medium()),
);
+ my $nonfree_is_needed = is_firmware_needed($o);
+
$o->ask_from_({ messages => join("\n",
N("Here you can enable more media if you want."),
msg_if_firmware_needed($o)
),
+ interactive_help_id => 'media_selection',
focus_first => sub { 1 } }, [
map {
my $medium = $_;
@@ -372,7 +453,10 @@ sub media_screen {
my ($distribconf, $medium_path) = @{$_->{mediacfg}};
my @media_types = split(':', $distribconf->getvalue($medium_path, 'media_type'));
my $parent = $distribconf->getvalue($distribconf->getvalue($medium_path, 'updates_for'), 'name');
- intersection(\@media_types, [ qw(backports debug source testing) ]) ? () :
+ my $non_regular_medium = intersection(\@media_types, [ qw(backports debug source testing) ]);
+ enable_nonfree_media($medium) if $nonfree_is_needed && !$non_regular_medium;
+ enable_core_32bit_media($medium) if arch() eq 'x86_64' && uefi_type() eq 'ia32' && !$non_regular_medium;
+ $non_regular_medium ? () :
+{
val => \$medium->{temp_enabled}, type => 'bool', text => $name,
help => $medium->{update} ? N("This medium provides package updates for medium \"%s\"", $parent) : $descriptions{$name},
@@ -384,7 +468,11 @@ sub media_screen {
};
} @{$urpm->{media}},
]);
+}
+sub enable_choosen_media {
+ my ($o) = @_;
+ my $urpm = $o->{packages};
# is there some media to enable?
my $todo;
@@ -406,6 +494,28 @@ sub media_screen {
);
}
+=item setPackages($o)
+
+=over 4
+
+=item * Initialize urpmi
+
+=item * Retrieves media.cfg
+
+=item * Offers to add supplementary media (according to the install method)
+
+=item * Offers to enable some disabled media
+
+=item * Ensure we have a kernel and basesystem
+
+=item * Flags package rates
+
+=item * Select default packages according to the computer
+
+=back
+
+=cut
+
sub setPackages {
my ($o) = @_;
@@ -433,7 +543,16 @@ sub setPackages {
}
install::pkgs::start_pushing_error();
- media_screen($o) if !$::auto_install;
+
+ # in auto-install mode, we enforce selected media, else we respect media.cfg's default:
+ if ($::auto_install && !is_empty_array_ref($o->{enabled_media})) {
+ # respect enabled/disabled media selection:
+ foreach my $medium (@{$urpm->{media}}) {
+ $medium->{temp_enabled} = member($medium->{name}, @{$o->{enabled_media}});
+ }
+ }
+ media_screen($o) if !$::auto_install || member('chooseMedia', @{$::o->{interactiveSteps}});
+ enable_choosen_media($o);
my @choosen_media = map { $_->{name} } grep { !$_->{ignore} } @{$urpm->{media}};
log::l("choosen media: ", join(', ', @choosen_media));
die "no choosen media" if !@choosen_media;
@@ -469,6 +588,7 @@ sub setPackages {
install::pkgs::select_by_package_names($urpm, [ $devel_kernel_pkg ], 1);
}
+ install::pkgs::select_by_package_names_or_die($urpm, default_bootloader(), 1) if !$o->{isUpgrade} && !$o->{match_all_hardware};
install::pkgs::select_by_package_names_or_die($urpm, ['basesystem'], 1);
my $rpmsrate_flags_was_chosen = $o->{rpmsrate_flags_chosen};
@@ -490,6 +610,12 @@ sub setPackages {
}
}
+=item remove_package_for_upgrade($o)
+
+Removes packages that must be uninstalled prior to upgrade
+
+=cut
+
sub remove_package_for_upgrade {
my ($o) = @_;
my $extension = $o->{upgrade_by_removing_pkgs_matching};
@@ -512,6 +638,12 @@ sub remove_package_for_upgrade {
log::l("Removing packages took: ", formatTimeRaw(time() - $time));
}
+=item count_files($dir)
+
+Returns the number of files in $dir
+
+=cut
+
sub count_files {
my ($dir) = @_;
-d $dir or return 0;
@@ -638,6 +770,23 @@ sub rpmsrate_always_flags {
$rpmsrate_flags_chosen;
}
+sub default_bootloader() {
+ require bootloader;
+ my (undef, $p) = bootloader::get_grub2_pkg();
+ if (is_uefi()) {
+ log::l("defaulting to grub2-efi");
+ } else {
+ log::l("defaulting to grub2");
+ }
+ [ $p ];
+}
+
+=item default_packages($o)
+
+Selects default packages to install according to configuration (FS, HW, ...)
+
+=cut
+
sub default_packages {
my ($o) = @_;
my @l;
@@ -654,18 +803,19 @@ sub default_packages {
add_n_log("method==nfs", "nfs-utils") if $o->{method} eq "nfs";
add_n_log("have RAID", "mdadm") if !is_empty_array_ref($o->{all_hds}{raids});
add_n_log("have LVM", "lvm2") if !is_empty_array_ref($o->{all_hds}{lvms});
- add_n_log("have crypted DM", "cryptsetup") if !is_empty_array_ref($o->{all_hds}{dmcrypts});
+ add_n_log("have crypted DM", qw(cryptsetup dmsetup)) if !is_empty_array_ref($o->{all_hds}{dmcrypts});
add_n_log("some disks are fake RAID", qw(mdadm dmraid)) if any { fs::type::is_dmraid($_) } @{$o->{all_hds}{hds}};
add_n_log("CPU needs microcode", "microcode_ctl") if detect_devices::hasCPUMicrocode();
- add_n_log("CPU needs cpufreq", 'cpupower') if detect_devices::hasCPUFreq();
+ add_n_log("either CPU or GFX needs firmware", is_firmware_needed($o)) if is_firmware_needed($o);
+ add_n_log("CPU needs cpupower", 'cpupower') if detect_devices::hasCPUFreq();
add_n_log("APM support needed", 'apmd') if -e "/proc/apm";
add_n_log("needed by hardware", detect_devices::probe_name('Pkg'));
my @ltmp = map { $_->{BOOTPROTO} eq 'dhcp' ? $_->{DHCP_CLIENT} || 'dhcp-client' : () } values %{$o->{net}{ifcfg}};
add_n_log("needed by networking", @ltmp) if @ltmp;
# will get auto selected at summary stage for bootloader:
- add_n_log("needed later at summary stage", qw(acpi acpid mageia-gfxboot-theme));
+ add_n_log("needed later at summary stage", qw(acpi acpid));
# will get auto selected at summary stage for firewall:
- add_n_log("needed for firewall/security", qw(shorewall mandi-ifw));
+ add_n_log("needed for firewall/security", qw(shorewall shorewall-ipv6 mandi-ifw));
# only needed for CDs/DVDs installations:
add_n_log("method='cdrom'", 'perl-Hal-Cdroms') if $o->{method} eq 'cdrom';
@@ -680,8 +830,6 @@ sub default_packages {
add_n_log("some fs is mounted with quota options", 'quota') if any { $_->{options} =~ /usrquota|grpquota/ } @{$o->{fstab}};
@ltmp = uniq(grep { $_ } map { fs::format::package_needed_for_partition_type($_) } @{$o->{fstab}});
add_n_log("needed by some fs", @ltmp) if @ltmp;
- add_n_log("some fs is NTFS-3G", 'ntfs-3g') if any { $_->{fs_type} eq 'ntfs-3g' } @{$o->{fstab}};
- add_n_log("some fs is btrfs", 'btrfs-progs') if any { $_->{fs_type} eq 'btrfs' } @{$o->{fstab}};
# handle locales with specified scripting:
my @languages = map { s/\@.*//; $_ } lang::langsLANGUAGE($o->{locale}{langs});
@@ -761,6 +909,13 @@ sub kdemove_desktop_file {
}
}
+sub log_system_info {
+ my ($o) = @_;
+ log::l("second stage install running (", drakx_version($o), ")");
+ log::l(sprintf("Virtualization=%s", detect_devices::virt_technology() || "none"));
+ log::l(sprintf("Is UEFI=%s", bool2yesno(is_uefi())));
+}
+
#-###############################################################################
#- auto_install stuff
@@ -776,9 +931,9 @@ sub g_auto_install {
my $o = {};
require install::pkgs;
- $o->{default_packages} = install::pkgs::selected_leaves($::o->{packages});
+ $o->{default_packages} = [ sort @{ install::pkgs::selected_leaves($::o->{packages}) } ];
- my @fields = qw(mntpoint fs_type size);
+ my @fields = qw(fs_type hd level mntpoint options parts size VG_name);
$o->{partitions} = [ map {
my %l; @l{@fields} = @$_{@fields}; \%l;
} grep {
@@ -794,6 +949,9 @@ sub g_auto_install {
#- deep copy because we're modifying it below
$o->{users} = $b_respect_privacy ? [] : [ @{$o->{users} || []} ];
+ # remember selected media:
+ local $o->{enabled_media} = [ map { $_->{name} } grep { !$_->{ignore} } @{$::o->{packages}{media}} ];
+
my @user_info_to_remove = (
if_($b_respect_privacy, qw(realname pw)),
qw(oldu oldg password password2),
@@ -828,9 +986,6 @@ sub getAndSaveAutoInstallFloppies {
eval { modules::load('loop') };
- if (arch() =~ /ia64/) {
- #- nothing yet
- } else {
my $mountdir = "$::prefix/root/aif-mount"; -d $mountdir or mkdir $mountdir, 0755;
my $param = 'kickstart=floppy ' . generate_automatic_stage1_params($o);
@@ -838,7 +993,7 @@ sub getAndSaveAutoInstallFloppies {
{
my $dev = devices::set_loop($img) or log::l("couldn't set loopback device"), return;
- find { eval { fs::mount::mount($dev, $mountdir, $_, 0); 1 } } qw(ext2 vfat) or return;
+ find { eval { fs::mount::mount($dev, $mountdir, $_, 0); 1 } } qw(ext2 vfat ntfs-3g) or return;
if (-e "$mountdir/menu.lst") {
# hd_grub boot disk is different than others
@@ -873,7 +1028,6 @@ sub getAndSaveAutoInstallFloppies {
}
rmdir $mountdir;
$img;
- }
}
@@ -903,7 +1057,7 @@ sub loadO {
my $o;
foreach (removable_media__early_in_install()) {
my $dev = devices::make($_->{device});
- foreach my $fs (arch() =~ /sparc/ ? 'romfs' : ('ext2', 'vfat')) {
+ foreach my $fs (qw(ext4 vfat ntfs-3g)) {
eval { fs::mount::mount($dev, '/mnt', $fs, 'readonly'); 1 } or next;
if (my $abs_f = find { -e $_ } "/mnt/$f", "/mnt/$f.pl") {
$o = loadO_($O, $abs_f);
@@ -1359,7 +1513,10 @@ sub take_screenshot {
}
my $nb = 1;
$nb++ while -e "$dir/$nb.png";
- system('fb2png', '/dev/fb0', "$dir/$nb.png", '0');
+ run_program::run('scrot', "$dir/$nb.png");
+
+ # help doesn't remember warning has been shown (one shot processes):
+ $warned ||= -e "$dir/2.png";
if (!$warned && !$nowarn) {
$warned = 1;
@@ -1398,8 +1555,8 @@ sub remove_advertising() {
}
sub disable_user_view() {
- substInFile { s/^UserView=.*/UserView=true/ } "$::prefix/etc/kde/kdm/kdmrc";
substInFile { s/^Browser=.*/Browser=0/ } "$::prefix/etc/X11/gdm/custom.conf";
+ #TODO: Needed for sddm ?
}
sub set_security {
@@ -1412,14 +1569,25 @@ sub set_security {
sub write_fstab {
my ($o) = @_;
- fs::write_fstab($o->{all_hds}, $::prefix)
- if !$::local_install && (!$o->{isUpgrade} || $o->{isUpgrade} =~ /redhat|conectiva/ || $o->{migrate_device_names});
+ return if $::local_install || $o->{isUpgrade} && $o->{isUpgrade} !~ /redhat|conectiva/ && !$o->{migrate_device_names};
+ fs::write_fstab($o->{all_hds}, $::prefix);
}
-sub adjust_files_mtime_to_timezone() {
- #- to ensure linuxconf does not cry against those files being in the future
- #- to ensure fc-cache works correctly on fonts installed after reboot
+=item adjust_files_mtime_to_timezone() {
+
+Fixes mtime of a couple important files according to timezone in order to:
+
+=over 4
+=item * to ensure linuxconf does not cry against those files being in the future
+
+=item * to ensure fc-cache works correctly on fonts installed after reboot
+
+=back
+
+=cut
+
+sub adjust_files_mtime_to_timezone() {
my $timezone_shift = run_program::rooted_get_stdout($::prefix, 'date', '+%z');
my ($h, $m) = $timezone_shift =~ /\+(..)(..)/ or return;
my $now = time() - ($h * 60 + $m * 60) * 60;
@@ -1515,4 +1683,8 @@ sub configure_pcmcia {
run_program::run("/lib/udev/pcmcia-socket-startup");
}
+=back
+
+=cut
+
1;