diff options
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | mdkonline.pm | 388 | ||||
-rwxr-xr-x | mdkupdate | 189 |
3 files changed, 4 insertions, 576 deletions
@@ -4,7 +4,8 @@ o do not skip first RPM check (change made in 2.16 in march 2007) o do not start network cyclic checks before first media test (#38991) o check for network just before first check - o reduce resident size by 1.5MB (5.4%) + o kill suppport for bundles + o reduce resident size by 9MB aka 30% (#31860) Version 2.38 - 20 March 2008, Thierry Vignaud diff --git a/mdkonline.pm b/mdkonline.pm index f31a8c70..1053f034 100644 --- a/mdkonline.pm +++ b/mdkonline.pm @@ -24,62 +24,13 @@ package mdkonline; use strict; -use MIME::Base64 qw(encode_base64); use lib qw(/usr/lib/libDrakX); -use c; use common; -use LWP::UserAgent; -use Net::HTTPS; -use HTTP::Request::Common; -use HTTP::Request; -use SOAP::Lite; use log; -#For debugging -use Data::Dumper; - -my ($service_proxy); - -my $testing = 1; - my $release_file = find { -f $_ } '/etc/mandriva-release', '/etc/mandrakelinux-release', '/etc/mandrake-release', '/etc/redhat-release'; -my ($product_file, $conf_file, $rootconf_file) = ('/etc/sysconfig/system', '/etc/sysconfig/mdkonline', '/root/.MdkOnline/hostconf'); - -my $uri = !$testing ? 'https://online.mandriva.com/soap' : 'https://online3.mandriva.com/soap/'; - -my $online_proxy = $service_proxy = $uri; - -my $useragent = set_ua('mdkonline'); - -sub is_proxy () { - return defined $ENV{http_proxy} ? 1 : defined $ENV{https_proxy} ? 2 : 0; -} - -my $proxy = is_proxy(); - -my $s = $proxy == 2 - ? SOAP::Lite->uri($uri)->proxy($service_proxy, proxy => [ 'http' => $ENV{https_proxy} ], agent => $useragent) - : $proxy == 1 - ? SOAP::Lite->uri($uri)->proxy($service_proxy, proxy => [ 'http' => $ENV{http_proxy} ], agent => $useragent) - : SOAP::Lite->uri($uri)->proxy($service_proxy, agent => $useragent); - -sub upgrade2v3() { - my $res; - if (-e $rootconf_file) { - my %oc = getVarsFromSh($rootconf_file); - my $res = soap_recover_service($oc{LOGIN}, '{md5}' . $oc{PASS}, $oc{MACHINE}, $oc{COUNTRY}); - print Data::Dumper->Dump([ $res ], [qw(res)]); - $res = check_server_response($res); - } - $res; -} - -sub get_rpmdblist() { - my $rpmdblist = `rpm -qa --queryformat '%{HDRID};%{N};%{E};%{V};%{R};%{ARCH};%{OS};%{DISTRIBUTION};%{VENDOR};%{SIZE};%{BUILDTIME};%{INSTALLTIME}\n'`; - $rpmdblist; -} sub md5file { require Digest::MD5; @@ -100,277 +51,11 @@ sub get_release() { ($r); } -sub set_ua { - my $package_name = shift; - my $qualified_name = chomp_(`rpm -q $package_name`); - $qualified_name; -} - -sub get_distro_type() { - my $r = cat_($release_file); - my ($archi) = $r =~ /\s+for\s+(\w+)/; - my ($name) = $r =~ /(corporate|mnf)/i; - { name => lc($name), 'arch' => $archi }; -} - -sub soap_create_account { - my $data = $s->registerUser(@_)->result; - log::explanations("creating account $_[0]"); - $data; -} - -sub soap_authenticate_user { - my $data = $s->authenticateUser(@_)->result; - log::explanations("authenticating account $_[0]"); - $data; -} - -sub soap_register_host { - my $data = $s->registerHost(@_)->result; - log::explanations("registering host $_[3] named $_[4] in country $_[5]"); - $data; -} - -sub soap_upload_config { - my $data = $s->setHostConfig(@_); - log::explanations("uploading config for host id $_[0] host key $_[1] class $_[2]"); - $data ? $data->result : undef; -} - -sub soap_query_bundle { - my ($wc, $bundle_name) = @_; - log::explanations("querying the bundle $bundle_name"); - my $data = $s->query($wc->{HOST_ID}, $wc->{HOST_KEY}, 'Software::get_bundle', $bundle_name)->result; - $data; -} -sub register_upload_host { - my ($login, $password, $boxname, $descboxname, $country) = @_; - my ($registered, $res); - my $wc = read_conf(); - if (!$wc->{HOST_ID} && -e $rootconf_file) { - $res = upgrade2v3(); - } elsif (!$wc->{HOST_ID} && !-e $rootconf_file) { - $registered = soap_register_host($login, $password, $boxname, $descboxname, $country); - print Data::Dumper->Dump([ $registered ], [qw(registered)]); - $res = check_server_response($registered); - } - return $res if defined $res && $res ne 'OK'; - #Reread configuration - $wc = read_conf() if $res eq 'OK'; - $res = prepare_upload_conf($wc); - $res; -} - -sub prepare_upload_conf { - my ($wc) = shift; - my ($uploaded, $res); - my $r = cat_($release_file); - my %p = getVarsFromSh($product_file); - my $rpmdblist = get_rpmdblist(); - $wc->{HOST_ID} and $uploaded = soap_upload_config($wc->{HOST_ID}, $wc->{HOST_KEY}, $r, $p{META_CLASS}, $rpmdblist); - $res = check_server_response($uploaded); - return $res; -} - -sub get_from_URL { - my ($link, $agent_name) = @_; - my $ua = LWP::UserAgent->new; - $ua->agent($agent_name . $useragent); - $ua->env_proxy; - my $request = HTTP::Request->new(GET => $link); - my $response = $ua->request($request); - $response; -} - -sub get_site { - my $link = shift; - $link .= join('', @_); - system("/usr/bin/www-browser " . $link . "&"); -} - -sub create_authenticate_account { - my $type = shift; - my @info = @_; - my ($response, $ret); - my $action = { - create => sub { eval { $response = soap_create_account(@info) } }, - authenticate => sub { eval { $response = soap_authenticate_user(@info) } } - }; - $action->{$type}->(); - $ret = check_server_response($response); - $ret; -} - -sub check_server_response { - my ($response) = shift; - my $hash_ret = { - 1 => [ N_("Security error"), N("Generic error (machine already registered)") ], - 2 => [ N("Database error"), N("Server Database failed\nPlease Try again Later") ], - 3 => [ N("Registration error"), N("Some parameters are missing") ], - 5 => [ N("Password error"), N("Wrong password") ], - 7 => [ N("Login error"), N("The email you provided is already in use\nPlease enter another one\n") ], - 8 => [ N("Login error"), N("The email you provided is invalid or forbidden") ], - 10 => [ N("Login error"), N("Email address box is empty\nPlease provide one") ], - 12 => [ N("Restriction Error"), N("Database access forbidden") ], - 13 => [ N("Service error"), N("Mandriva web services are currently unavailable\nPlease Try again Later") ], - 17 => [ N("Password error"), N("Password mismatch") ], - 20 => [ N("Service error"), N("Mandriva web services are under maintenance\nPlease Try again Later") ], - 22 => [ N("User Forbidden"), N("User account forbidden by Mandriva web services") ], - 99 => [ N("Connection error"), N("Mandriva web services not reachable") ] - }; - foreach my $num ([9, 8], [21, 20]) { $hash_ret->{$num->[0]} = $hash_ret->{$num->[1]} } - # print Data::Dumper->Dump([ $response ], [qw(response)]); - my $code = $response->{code} || '99'; - my $answer = $response->{code} eq 0 ? 'OK' : $hash_ret->{$code} ? $hash_ret->{$code}[0] . ' : ' . $hash_ret->{$code}[1] . "\n\n" . $response->{message} : $response->{message}; - $answer eq 'OK' and write_conf($response) if !$<; - log::explanations(qq(the server returned "$answer")); - return $answer; - -} - -sub check_valid_email { - my $email = shift; - my $st = $email =~ /^[a-z][a-z0-9_\-]*(\.[a-z][a-z0-9_]+)?@([a-z][a-z0-9_\-]+\.){1,3}(\w{2,4})(\.[a-z]{2})?$/ix ? 1 : 0; - return $st; -} - -sub check_valid_boxname { - my $boxname = shift; - return 0 if length($boxname) >= 40; - my $bt = $boxname =~ /^[a-zA-Z][a-zA-Z0-9_.]+$/i ? 1 : 0; - $bt; -} - -sub rpm_ver_parse { - my ($ver) = @_; - my @verparts; - while ($ver ne "") { - if ($ver =~ /^([A-Za-z]+)/) { # leading letters - push(@verparts, $1); - $ver =~ s/^[A-Za-z]+//; - } elsif ($ver =~ /^(\d+)/) { # leading digits - push(@verparts, $1); - $ver =~ s/^\d+//; - } else { # remove non-letter, non-digit - $ver =~ s/^.//; - } - } - return @verparts; -} - -sub rpm_ver_cmp { - my ($a, $b) = @_; - # list of version/release tokens - my @aparts; - my @bparts; - # individual token from array - my ($apart, $bpart, $result); - if ($a eq $b) { - return 0; - } - @aparts = rpm_ver_parse($a); - @bparts = rpm_ver_parse($b); - while (@aparts && @bparts) { - $apart = shift (@aparts); - $bpart = shift (@bparts); - if ($apart =~ /^\d+$/ && $bpart =~ /^\d+$/) { # numeric - if ($result = $apart <=> $bpart) { - return $result; - } - } elsif ($apart =~ /^[A-Za-z]+/ && $bpart =~ /^[A-Za-z]+/) { # alpha - if ($result = $apart cmp $bpart) { - return $result; - } - } else { # "arbitrary" in original code - my $rema = shift(@aparts); - my $remb = shift(@bparts); - if ($rema && !$remb) { return 1 } elsif (!$rema && $remb) { return -1 } - #return -1; - } - } - # left over stuff in a or b, assume one of the two is newer - if (@aparts) { return 1 } elsif (@bparts) { return -1 } else { return 0 } -} - -sub soap_recover_service { - my $data = $s->recoverHostFromV2(@_)->result; - $data; -} - -sub soap_get_task { - my $data = $s->getTask(@_)->result; - $data; -} - -sub soap_return_task_result { - my $data = $s->setTaskResult(@_)->result; - $data; -} - -sub soap_get_updates_for_host { - my $data = $s->getUpdatesForHost(@_)->result; - $data; -} - -sub soap_is_new_update_for_distro { - my $data = $s->isNewUpdateForDistribution(@_)->result; - $data; -} - -sub mv_files { - my ($source, $dest) = @_; - -e $source and system("mv", $source, $dest); -} - sub clean_confdir() { my $confdir = '/root/.MdkOnline'; system "/bin/rm", "-f", "$confdir/*log.bz2", "$confdir/*log.bz2.uue", "$confdir/*.dif $confdir/rpm_qa_installed_before", "$confdir/rpm_qa_installed_after"; } -sub hw_upload { - my ($login, $passwd, $hostname) = @_; - my $hw_exec = '/usr/sbin/hwdb_add_system'; - -x $hw_exec && !-s '/etc/sysconfig/mdkonline' and system("HWDB_PASSWD=$passwd $hw_exec $login $hostname &"); -} - -sub automated_upgrades() { - output_p "/etc/cron.daily/mdkupdate", - qq(#!/bin/bash -if [ -f $conf_file ]; then /usr/sbin/mdkupdate --auto; fi -); - chmod 0755, "/etc/cron.daily/mdkupdate"; -} - -sub read_conf() { - my %wc = getVarsFromSh($conf_file); - \%wc; -} - -sub write_conf { - my $response = shift; - write_wide_conf($response); -} - -sub get_date() { - my $date = `date --iso-8601=seconds`; # output date/time in ISO 8601 format. Ex: 2006-02-21T17:04:19+0100 - $date = chomp_($date); - $date; -} - -sub write_wide_conf { - my ($soap_response) = shift; - #print Data::Dumper->Dump([ $soap_response ], [qw(soap_response)]); - my $date = get_date(); my $conf_hash; - %$conf_hash = getVarsFromSh($conf_file); - $conf_hash->{uc($_)} = $soap_response->{data}{$_} foreach keys %{$soap_response->{data}}; - #print Data::Dumper->Dump([ $conf_hash ], [qw(conf_hash)]); - $conf_hash->{DATE_SET} = $date; - foreach my $alias (['email', 'user_email'], ['customer_id', 'user_id']) { - exists $conf_hash->{uc($alias->[0])} and $conf_hash->{uc($alias->[1])} = $conf_hash->{uc($alias->[0])}; - } - setVarsInSh($conf_file, $conf_hash, qw(USER_EMAIL USER_ID HOST_NAME HOST_ID HOST_KEY HOST_DESC HOST_MOBILE VERSION DATE_SET)); -} - sub is_running { my ($name) = @_; my $found; @@ -384,77 +69,4 @@ sub is_running { $found; } -# Romain: you need to finish those dns functions or drop them -sub get_configuration { - my $_in = shift; - my $config_file = '/etc/sysconfig/mdkonline'; - my %conf;my $ret; - # check local config file - if (! (-e $config_file) || ! (-s $config_file)) { - %conf = get_conf_from_dns(); - print "from dns:\n", Dumper(%conf), "\n"; - } else { - %conf = getVarsFromSh($config_file); - if (defined $conf{MACHINE} && !defined $conf{VERSION}) { - $ret = upgrade_to_v3(); - print "\n", $ret, "\n"; - if ($ret == 1) { - # reload config - %conf = getVarsFromSh($config_file); - } - else { - # TODO what do we do now? email warning? support? forget it? - %conf = undef; - } - } - } - - # now, a valid working config file is loaded - if (defined $conf{MOBILE} && $conf{MOBILE} eq 'TRUE') { - # client is mobile: we check for any dns-declared local option - # (like, a local update mirror) - # TODO set precedence rules. user may not want/have the right to - # follow local network rules (security of the update process). - # depends on host config, and on server commands. - my $sd = new Discovery; - my $info = $sd->search; - if ($info) { - # TODO - } - else {} # nothing to do - } - %conf; -} - -sub register_from_dns { - my $dnsconf = shift; - my ($hostinfo, $country ); - my $user = $dnsconf->{user}{name}; - my $pass = $dnsconf->{user}{pass}; - my $hostname = chomp_(`hostname`); - # TODO change SOAP proxy to the one indicated at $dnsconf->{service} before - # TODO wrap all soap calls into an object so we can update the proxy on the fly? - my $res = mdkonline::soap_register_host($user, $pass, $hostname, $hostinfo, $country); - if ($res->{code}) { - $res->{data}{service} = $dnsconf->{service}; - return mdkonline::save_config($res->{data}); - } -} - -sub get_conf_from_dns() { - my $sd = new Discover; - my $info = $sd->search; - my $ret; - if ($info) { - if (defined $info->{user}{name} && defined $info->{user}{pass} && $info->{user}{name} ne '' && $info->{user}{pass} ne '') { - #print Data::Dumper->Dump([ $info ], [qw(info)]); - # TODO check service certificate - $ret = mdkonline::register_from_dns($info); - if ($ret) { - return $ret; - } - } - } -} - 1; @@ -47,15 +47,9 @@ require_root_capability(); my $confdir = '/root/.MdkOnline'; my $conffile = "$confdir/mdkupdate"; -my $difflog = '/var/tmp/diff.log'; my $logfile = '/var/tmp/mdkupdate.log'; -my $currentrpm = "$confdir/rpm_qa_installed_current"; -my $afterrpm = "$confdir/rpm_qa_installed_after"; - -my $startpage = 'http://start.mandriva.com/'; - my $CLIENT_VERSION = "4"; my $YEARS = "2002-2006"; @@ -75,194 +69,31 @@ usage: ") . N(" --mnf - launch mnf specific scripts. ") . N(" --noX - text mode version of Mandriva Update. ") . N(" --debug - log what is done -") . N(" --bundle file.bundle - parse and install package from .bundle metainfo file. "); exit(0); } -my ($auto, $mnf, $noX, $bundle, $debug); +my ($auto, $mnf, $noX, $debug); my %options = ( 'auto' => \$auto, 'mnf' => \$mnf, 'noX' => \$noX, 'd|debug' => \$debug, - 'b|bundle:s' => sub { $bundle = $_[1] || 'webbundle' } , 'h|help' => \&usage, ); GetOptions(%options); -# workaround an issue with browsers that sometimes drop the --bundle option: -$bundle = shift @ARGV if $ARGV[0] =~ /\.bundle$/; - -$bundle eq "webbundle" and mdkonline::get_site($startpage), exit(0); my $in; -$bundle || $noX and $in = interactive->vnew; +$noX and $in = interactive->vnew; -my $result; -my $wc = mdkonline::read_conf(); -e $logfile and system "/bin/rm", $logfile; -if (!$bundle) { - my ($release) = mdkonline::get_release(); - my $ret = update_pkgs(); $ret == 1 or output_p($logfile, "[mdkupdate] Error 100: Packages failed to upgrade"); - rpm_qa($afterrpm); - my $wc = mdkonline::read_conf(); clean_dir(); -} else { - log::explanations("managing the $bundle bundle"); - if (-d '/live/media/loopbacks') { - $in->ask_warn(N("Warning"), - #-PO: here Live Install is currently *NOT* translated on the desktop, so it's better to keep as it: - N("You first need to install the system on your harddrive with the 'Live Install' wizard.")); - $in->exit(1); - } - my $w = $in->wait_message(N("Please wait"), N("Preparing...")); - my %bundle_vars = getVarsFromSh($bundle); - rm_rf($bundle); - - my %mapping = ( - USER => 'USER_EMAIL', - #SESSION_ID => 'HOST_KEY', - ); - while (my ($bundle_varname, $onlinesrv_varname) = each %mapping) { - $wc->{$onlinesrv_varname} = $bundle_vars{$bundle_varname}; - } - if (!($wc->{HOST_ID} && $wc->{HOST_KEY})) { - use lang; - my $hostname = chomp_(cat_('/proc/sys/kernel/hostname')); - my $reg_host = mdkonline::soap_register_host($bundle_vars{USER}, $bundle_vars{PASS}, $hostname, ' ', lang::read()->{country}); - my $res = mdkonline::check_server_response($reg_host); - if ($res ne 'OK') { - undef $w; - $in->ask_warn(N("Error"), N("Failed to authenticate to the bundle server:\n\n%s", $reg_host->{message})); - exit(3); - } - # we've no previous config so write one so that write_wide_conf() do not miss some fields: - setVarsInSh('/etc/sysconfig/mdkonline', { - USER_EMAIL => $bundle_vars{USER}, - HOST_NAME => $hostname, - }); - mdkonline::write_wide_conf($reg_host); - } - - $wc = mdkonline::read_conf(); - $wc->{USER_EMAIL} or die("Configuration not uploaded to Mandriva Online"); - - my $res = mdkonline::prepare_upload_conf($wc); - if ($res ne 'OK') { - undef $w; - log::explanations("we failed to be accepted by the server: $res"); - $in->ask_warn(N("Error"), N("An error occurred") . "\n\n" . $res); - } - - if ($bundle_vars{CLIENT_VERSION} > $CLIENT_VERSION) { - log::explanations("the client is too old in order to install the bundle $bundle_vars{BUNDLE}"); - $in->ask_warn(N("Warning"), N("The version of the Mandriva Online client is too old. - -You need to update to a newer version. You can get a new one from http://start.mandriva.com")); - $in->exit(1); - } - my $bundle_info = mdkonline::soap_query_bundle($wc, $bundle_vars{BUNDLE}); - $res = mdkonline::check_server_response($bundle_info); - print Data::Dumper->Dump([ $bundle_info ], [ qw(bundle_info) ]); - if ($res eq 'OK') { - my @bundles; - $w = $in->wait_message(N("Please wait"), N("Preparing...")); - my ($mirrors, $bundle) = ($bundle_info->{data}{mirrors}, $bundle_info->{data}{bundle}); - $bundle =~ s/-[^-]*-[^-]*\.[^.]*\.rpm$//; - push @bundles, $bundle; - my %mirrors = add_mirrors($in, $w, $mirrors, \%bundle_vars); - undef $w; - install_pkgs($in, \@bundles, (find { /^bundle/ } keys %mirrors), - { is_bundle => 1, - auto_select => ($bundle_vars{POST} =~ /AUTO_SELECT/ ? 1 : 0), - medias => [ keys %mirrors ], - }); - } else { - undef $w; - log::explanations("we did not got back a bundle: $bundle_info->{message}"); - $in->ask_warn(N("Error"), N("An error occurred") . "\n\n" . $res . "\n\n" . $bundle_info->{message}); - } -} - -sub add_mirrors { - my ($in, $w, $mirrors, $bundle_vars, $option) = @_; - foreach my $mirror (@$mirrors) { - next if $mirror->{mode} eq 'anon'; # nothing to do - if ($mirror->{mode} eq 'auth') { - # add "user:pass@" substring if needed: - # user password & login provided by server on those provided with the bundle: - $bundle_vars->{USER} = $mirror->{user} if $mirror->{user}; - $bundle_vars->{PASS} = $mirror->{pass} if $mirror->{pass}; - my $encoded_login = uri_escape($bundle_vars->{USER}); - my $encoded_pass = uri_escape($bundle_vars->{PASS}); - $mirror->{url} =~ s!^([^:]*)://!\1://$encoded_login:$encoded_pass@!; - } else { # unknown method, aborting - undef $w; - log::explanations("we got a bad bundle"); - $in->ask_warn(N("Error"), N("This bundle is not well formated. Aborting.")); - $in->exit(1); - } - } - my %mirrors = map { $_->{name} => join('@', grep { $_ } $_->{auth}, $_->{url}) } @$mirrors; - add_media($_, $mirrors{$_}, 'media_info/synthesis.hdlist.cz', $option) foreach keys %mirrors; - %mirrors; -} - -sub install_pkgs { - my ($in, $choosed, $media_name, $o_options) = @_; - $o_options ||= {}; - my $w = $in->wait_message(N("Please wait"), N("Installing packages ...\n")) if !$o_options->{is_bundle}; - my $program = $o_options->{no_X} ? '/usr/sbin/urpmi' : '/usr/bin/gurpmi'; - eval { - if (!$o_options->{is_bundle}) { - log::explanations("applying the updates"); - system $program, "--auto", "--media", $media_name, @$choosed; - } else { - log::explanations("installing the bundle"); - system $program, '--auto', if_($o_options->{auto_select}, "--auto-select"), - if_($o_options->{medias}, "--media", join(',', @{$o_options->{medias}})), - "--searchmedia", $media_name, @$choosed; - } - $? == 0 or die N("Unable to update packages from update_source medium.\n"); - }; - undef $w; -} - -sub my_fullname { - return '?-?-?' unless ref $_[0]; - my ($name, $version, $release) = $_[0]->fullname; - "$name-$version-$release"; -} -sub add_media { - my ($media_name, $mirror, $hdlist, $option) = @_; - log::explanations("removing/adding the media $media_name"); - eval { - system "/usr/sbin/urpmi.removemedia", $media_name; - # use curl because wget sometime fail on https url - system "/usr/sbin/urpmi.addmedia", if_($option, $option), '--curl', $media_name, $mirror, "with", $hdlist; - }; - $@ and die "Problem adding bundle media with urpmi"; -} - -sub prepare_media { - my $mirror = shift; - my ($r, $da, $is_x8664, $dist_name); - ($r) = mdkonline::get_release(); - # retrieve dist and arch from /etc/mandrakelinux file - $da = mdkonline::get_distro_type(); - my ($path2new_arch, $path2new_synthesis) = $r <= 10.0 ? ('/RPMS/', '../base/synthesis.hdlist.cz') : ('/main_updates/', 'media_info/synthesis.hdlist.cz'); - #sometimes server returns the full link http:// or ftp:// - ($is_x8664) = $da->{arch} =~ /(x86_64)/; - $dist_name = $da->{name}; - my $fullpath2mir = if_($mirror !~ m!^(?:http|ftp)://! , "ftp://") . $mirror . if_($is_x8664, "/$is_x8664") . if_($dist_name, "/$dist_name") . "/$r" . $path2new_arch; - add_media('update_source', $fullpath2mir, $path2new_synthesis, '--update'); -} sub update_pkgs { my (@pkgs) = @_; @@ -274,23 +105,7 @@ sub update_pkgs { return 1; } -sub get_rpm_diff() { - my $isdif = `sdiff -s $afterrpm $currentrpm`; - $isdif and output_p($difflog, $isdif), return 1; - return 0; -} - -sub new_rpm_base() { - -f $afterrpm and system('/bin/mv', $afterrpm, $currentrpm); -} - sub clean_dir() { - new_rpm_base(); mdkonline::clean_confdir(); output_p($logfile, 'OK'); } - -sub rpm_qa { - my ($file) = @_; - output($file, chomp_(join('', sort(`rpm -qa`)))); -} |