home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
boot
/
i386
/
root
/
usr
/
share
/
YaST2
/
modules
/
OSRPkg.ycp
< prev
next >
Wrap
Text File
|
2006-11-29
|
26KB
|
1,041 lines
/**
* File: OSRPkg.ycp
* Module: repair
* Summary: Packages check
* Authors: Johannes Buchhold <jbuch@suse.de>
*
* $Id: OSRPkg.ycp 33121 2006-09-26 12:43:41Z jsuchome $
*
* Provide osr mode information.
*/
{
module "OSRPkg";
textdomain "repair";
import "DefaultDesktop";
import "Kernel";
import "Mode";
import "Report";
import "Wizard";
import "Popup";
import "Stage";
import "OSRCommon";
import "OSRSystem";
import "OSRExecute";
import "OSRLogFile";
import "OSRPopup";
import "OSRPkgUI";
import "OSRPkgVerify";
/**
* Package database files
*/
list<string> rpm3_db_files = [
"/var/lib/rpm/conflictsindex.rpm",
"/var/lib/rpm/fileindex.rpm",
"/var/lib/rpm/groupindex.rpm",
"/var/lib/rpm/nameindex.rpm",
"/var/lib/rpm/packages.rpm",
"/var/lib/rpm/providesindex.rpm",
"/var/lib/rpm/requiredby.rpm",
"/var/lib/rpm/triggerindex.rpm"
];
/**
* Package database files (version >=4)
*/
list<string> rpm4_db_files = [
"/var/lib/rpm/Basenames",
"/var/lib/rpm/Conflictname",
"/var/lib/rpm/Dirnames",
"/var/lib/rpm/Filemd5s",
"/var/lib/rpm/Group",
"/var/lib/rpm/Installtid",
"/var/lib/rpm/Name",
"/var/lib/rpm/Packages",
"/var/lib/rpm/Providename",
"/var/lib/rpm/Provideversion",
"/var/lib/rpm/Pubkeys",
"/var/lib/rpm/Requirename",
"/var/lib/rpm/Requireversion",
"/var/lib/rpm/Sha1header",
"/var/lib/rpm/Sigmd5",
"/var/lib/rpm/Triggername"
];
/**
* Current package database files
*/
list<string> rpm_db_files = rpm3_db_files;
/**
* if a backup (YaST) of the package database was
* created.
* Save rpm?_db_files[X] -> rpm?_db_files[X].old
*/
boolean backup_created = false;
/**
* Mount point where the target system is mounted.
*/
global string root_mountpoint = "";
/**
* Help text to show errors.
*/
global string help_text = "";
/**
* Error text.
*/
global string error_text = "";
/**
* Dialog description for the install missing or damaged packages.
*/
global list install_missing_dialog_data = [];
/**
* Missing packages database files.
*/
global list <string> not_found_files = [];
/**
* Not installed base packages or damaged packages.
*/
global list <string> missing_packages = [];
/**
* All new installed packages.
*/
list <string> reinstalled_packages = [];
/**
* This will be local when converted to a Module::
* Has Pkg::TargetInit run?
*/
boolean target_initialized = false;
/**
* Before first opening pkg database, we need to close it preventively
* (because it could be opened with a different root path).
* This variable says, if it is first time now.
*/
boolean first_time_openpkg = true;
/**
* This will be local when converted to a Module::
* Has Pkg::SourceStartCache run?
*/
boolean source_initialized = false;
boolean package_db_repaired = false;
list<string> architecture_packages = [];
// list of packages in minimal selection (read it just after pkg target is
// initialized to avoid bug #30423)
list<string> minimal_selection = [];
// general help text about package database
string default_package_help = _("
<p>The package database administers all
information of the installed software packages.
The most common way to add a new program or library
to a Linux system is to install a new package.
In doing so, the install routine copies all files of the
package to the target and registers the package in
the package database.</P>
");
// general help text about damaged package database
string damaged_package_help = _("
<P>If the package database is damaged, installing
and removing packages or updating the system
is not possible.</P>
");
/**
* Reset the module settings.
*/
global define void Reset()``{
not_found_files = [];
error_text = "";
help_text = "";
root_mountpoint = "";
missing_packages = [];
architecture_packages = [];
package_db_repaired = false;
reinstalled_packages = [];
install_missing_dialog_data = [];
if (target_initialized )
{
target_initialized = ! Pkg::TargetFinish ();
}
// don't reset source_initialized
// don't reset reinstalled_packages
OSRPkgUI::Reset();
OSRPkgVerify::Reset();
}
/**
* Constructor.
*/
global define void OSRPkg()``{
Reset();
}
define list<string> get_minimal_selection () ``{
if (Mode::test ())
{
return [ "test" ];
}
if (minimal_selection == [] || minimal_selection == nil)
{
DefaultDesktop::SetDesktop ("text");
list<string> pats = DefaultDesktop::PatternsToSelect ();
foreach (string p, pats, {
list<map> descrs = Pkg::ResolvableDependencies (p,`pattern, "");
foreach (map descr, descrs, {
foreach (map dep, (list<map>)descr["dependencies"]:[], {
if (dep["res_kind"]:"" == "package" &&
dep["dep_kind"]:"" == "requires")
{
minimal_selection = add (minimal_selection,
dep["name"]:"");
}
});
});
});
}
return minimal_selection;
}
/**
* Open the package database.
*/
global define boolean OpenPkg( string root )``{
if (Mode::test ()) return true;
import "Packages";
y2milestone("Open pkg database with target system -%1-", root );
if (root != "" && root != nil ) root_mountpoint = root;
// open the package source
if (! Stage::initial () )
{
source_initialized = source_initialized ||
Pkg::SourceStartCache (true) != [];
}
else
{
if (! source_initialized )
{
y2milestone("Calling package module");
//change root for the Package module call
OSRSystem::SetOrgRoot();
Packages::Init (true);
architecture_packages = Packages::ComputeSystemPackageList();
y2milestone("Add architecture packages %1",
architecture_packages );
//reset root environment
OSRSystem::ChangeRoot(root);
source_initialized = true;
}
}
// open target system for Pkg access
if (!target_initialized)
{
if (first_time_openpkg)
{
y2milestone ("first time initializig -> finish target before");
Pkg::TargetFinish ();
first_time_openpkg = false;
}
target_initialized = Pkg::TargetInit ( root, false);
get_minimal_selection ();
}
// something failed
if (! target_initialized || ! source_initialized )
{
y2error("Opening the package database failed. ");
y2error("Target is initialised: %1", target_initialized);
y2error("Source is initialised: %1", source_initialized);
// build help and error text for following repair dialog
help_text = default_package_help + damaged_package_help;
// error popup
error_text = _("
Cannot open the package database.
Try rebuilding the package
database or reverting to a backup.
");
}
return target_initialized && source_initialized;
}
/**
* Check if target product is the same as the source (bug #45306)
* @return true if product are the same
*/
global define boolean CheckProductVersions () {
if (Mode::test ()) return true;
integer source_id = 1;
// TODO we could use Packages::theSources
list curr_sources = Pkg::SourceGetCurrent (true);
source_id = curr_sources[0]:source_id;
map source_product = Pkg::SourceProduct (source_id);
list all_products = Pkg::TargetProducts ();
map target_product = all_products[0]:$[];
y2debug ("source product: %1", source_product);
y2debug ("target_product: %1", target_product);
if (source_product["product"]:"" != target_product["product"]:"")
{
y2error("target product (%1) is different from source product (%2)",
target_product["product"]:"", source_product["product"]:"");
y2warning ("source product: %1", source_product);
y2warning ("target_product: %1", target_product);
return false;
}
return true;
}
/**
* Return false if db files are missing.
* Save missing files in the list not_found_files.
*/
global define boolean CheckDB (string root )``{
if (root != "" && root != nil ) root_mountpoint = root;
not_found_files = [];
// Now the version of pkg databse is checked
rpm_db_files = rpm3_db_files;
if (OSRExecute::Command (.local.bash, sformat("/usr/bin/test -f %1",
root_mountpoint + "/var/lib/rpm/Packages")))
rpm_db_files = rpm4_db_files;
// check all database files
foreach(string file, rpm_db_files, ``{
if (!OSRExecute::Command (.local.bash,
sformat("/usr/bin/test -f %1", root_mountpoint + file)))
not_found_files = add(not_found_files, file);
});
// if files are missing
if (size( not_found_files ) > 0 )
{
help_text = default_package_help + damaged_package_help;
// error message: files (%1) not found
error_text = sformat(_("
The package database was checked.
The following files that belong
to the package database were not
found.
%1
"),mergestring(not_found_files,"\n"));
}
else
{
// try to open the database.
// if open fails OpenPkg set help and error text
return OpenPkg( root_mountpoint );
}
return size( not_found_files ) == 0;
}
/**
* Make a backup of the package database
* files.
*/
define boolean backup_package_db()``{
// only create one package at the
// first call of backup_package_db
if (backup_created ) return true;
list<boolean> ret = [];
foreach(string file, rpm_db_files, ``{
string f = root_mountpoint + file;
if (!contains (not_found_files , file))
ret = add (ret, OSRExecute::Command (.local.bash,
sformat("/bin/cp %1 %1.old",f)));
});
// if not error was found
if (size(filter(boolean r, ret, ``( r != true ))) == 0 )
{
backup_created = true;
}
return backup_created;
}
/**
* Revert the YaST backup of the package database.
*/
define boolean revert_packages_backup()``{
if (! backup_created ) return false;
list<boolean> ret = [];
foreach (string file, rpm_db_files, ``{
string f = root_mountpoint + file;
//if orginal file exists
if (! contains( not_found_files , file))
{
ret = add( ret , OSRExecute::Command(.local.bash, sformat("/bin/cp %1.old %1",f)));
}
});
// if not error was occurred
if (size(filter(boolean r, ret, ``( r != true ))) == 0 )
{
Report::Message(_("\nReverting to the backup was successful.
"));
return true;
}
else
{
// error popup
Report::Error(_("
Reverting to the backup was not
successful. Select another
backup or try to rebuild
the package database.
"));
return false;
}
};
/**
* Rebuild the package database.
*/
define boolean rebuild_package_db( boolean show_message )``{
boolean ret = true;
UI::OpenDialog (`VBox (
`VSpacing(1),
// wait popup label
`Label(_("Rebuilding the package database...")),
`VSpacing(1)
));
if (backup_created || size(not_found_files ) > 0 )
{
// some package database files are missing
if ((! Mode::test ()) && size( not_found_files ) > 0 )
{
ret = WFM::Execute (.local.bash,
sformat("/bin/rpm --root %1 --initdb",root_mountpoint))== 0;
}
// rebuild package database
ret = ret && WFM::Execute (.local.bash,
sformat("/bin/rpm --root %1 --rebuilddb",root_mountpoint)) == 0;
package_db_repaired = true;
UI::CloseDialog();
if (show_message )
{
if (ret )
{
Report::Message(_("
Successfully rebuilt the
package database.
"));
}
else
{
Report::Error(_("
Could not rebuild the package
database. Revert to a backup of
the package database.
"));
}
}
}
else {
UI::CloseDialog();
ret = false;
}
return ret;
}
/**
* Revert a backup of the package database
* from /var/adm/backup/rpmdb.
*/
define boolean revert_daily_backup()``{
if (!backup_created && size(not_found_files) == 0 )
return false;
boolean ret = false;
string file_path = "packages.rpm";
string backup_path = (string)
SCR::Read(.sysconfig.backup.RPMDB_BACKUP_DIR);
if (backup_path == "" || backup_path == nil )
{
y2error ("No sysconfig backup path found. Use default /var/adm/backup/rpmdb");
backup_path = "/var/adm/backup/rpmdb";
}
list<string> files = (list<string>) SCR::Read(.target.dir, backup_path);
files = filter(string f, files, ``(substring(f, 0, size(file_path)) == file_path ));
y2milestone("Found files for backup: %1", files );
//packages.rpm-20021105.gz
list<string> dates = maplist(string f, files, ``(substring(f, size(file_path)+1 , 8)));
dates = sort(string f, string ff, dates, ``( f > ff ));
dates = maplist(string f, dates, ``(sformat("%1.%2.%3", substring( f,0,4),
substring(f,4,2),
substring(f,6,2))));
list<list> items = maplist(string f, dates, ``([f,""]));
// no backup was found, %1 is path
if (size(items ) == 0 )
{
Report::Error(sformat(_("
No package database backup files
found. Normally, a cron job creates
daily backups of the package database and
stores the backups in the directory
%1. However, no backup files could
be found in this directory.
Try another repair method.
"),backup_path));
return false;
}
string selected = OSRPopup::RadioButtonGroupText(_("Backup to Use"),
_("
Several backups of the
package database were found.
Select the date (YYYY/MM/DD)
of the backup to which
to revert.\n"), items, dates[0]:"", "", false);
y2milestone("The selected item %1", selected);
if (selected != "" )
{
selected = find(string f, files, ``(issubstring(f, mergestring(splitstring(selected, "."),"") )));
selected = backup_path + "/"+selected;
if (OSRExecute::Command(.local.bash, sformat("/usr/bin/test -f %2/%1", selected, root_mountpoint )))
{
if (! Mode::test () && WFM::Execute(.local.bash, sformat("/bin/gunzip < %2/%1 \
> %2/var/lib/rpm/packages.rpm", selected ,root_mountpoint )) == 0 )
{
if (rebuild_package_db(false) )
{
Report::Message(_("
Reverting to the backup of the package
database was successful.
"));
ret = true;
}
}
else
{
Report::Error(_("
Reverting to the backup of the package
database was not successful.
"));
}
package_db_repaired = true;
}
else
{
//should never happpen
y2error("Selected package update file not found");
}
}
return ret;
}
/**
* Repair or initialise a damaged package
* damaged. Call CheckDB before.
*/
global define symbol RepairDB()``{
string repair_header = _("Repair Package Database");
if (! backup_package_db())
{
y2error("Creating backup of package db was not successful");
if (size(not_found_files ) == 0 ) return `error;
}
term r_options = `VBox (
`Left (
// popup headline
`Label(_("Repair Method"))),
`VSpacing(0.5),
`Left (
// radio button label
`RadioButton(`id(`rebuild), _("Rebuild Package Database"),true)
),
`Left (
// radio button label
`RadioButton(`id(`daily), _("Revert to Daily Backup"), false)
)
);
term last_entry = `RadioButton(`id(`revert ));
if (! package_db_repaired )
last_entry = add( last_entry , `opt(`disabled ));
last_entry = add( last_entry, _("Revert to Orginal Package Database (saved by YaST)"));
last_entry = add( last_entry, false);
r_options = add( r_options, last_entry);
if (! OSRPopup::OpenMainRepairDialog( repair_header , error_text, r_options ))
{
y2error("Could not open main dialog for repairing package database.");
return `error;
}
symbol ret = `ok;
repeat
{
ret = (symbol)UI::UserInput();
symbol selected = (symbol)UI::QueryWidget(`id(`rb), `CurrentButton);
if (ret == `help )
{
Popup::LongText( OSRPopup::help_headline , `RichText( help_text ), 50, 20);
}
else if (ret == `ok )
{
UI::CloseDialog();
boolean rret = false;
// execute selected repair method
if (selected == `rebuild)
rret = rebuild_package_db(true);
else if (selected == `daily)
rret = revert_daily_backup();
else if (selected == `revert)
rret = revert_packages_backup();
if (!rret)
{
if (!OSRPopup::OpenMainRepairDialog (repair_header,
error_text, r_options))
{
y2error("Could not open main dialog");
return `error;
}
ret = `again;
}
}
} until( ret == `cancel || ret == `abort || ret == `ok );
if (ret != `ok ) UI::CloseDialog();
return ret;
}
/**
* Return all packages which should be verified
*/
define list<string> get_verify_packages(string what ) ``{
list<string> ret = [];
// return all packages
if (what == "all" )
{
ret = Pkg::GetPackages(`installed, true);
}
// return base packages only
else if (what == "base")
{
list<string> minimal = get_minimal_selection ();
list<string> special = [];
minimal = filter (string p, minimal, ``( Pkg::IsAvailable(p)));
ret = (list<string>) union (minimal, special) ;
}
else
{
y2error("Parameter what not valid. Only all or base are allowed.");
ret = nil;
}
if (ret != nil )
{
ret = (list<string>) union (ret, architecture_packages );
}
return ret;
}
/**
* Check if all minimal required packages are installed.
*/
global define boolean CheckMinimum(string root )``{
// reset missing package
missing_packages = [];
if (root != "" && root != nil ) root_mountpoint = root;
if (! OpenPkg( root_mountpoint ))
{
y2error("Opening the package database failed. Checking minimal package selection is not possible.");
y2error("Please call CheckDB before calling CheckMinimum");
return false;
}
list<string> installed_packages = Pkg::GetPackages(`installed, true);
list<string> minimal_packages = get_verify_packages( "base" );
missing_packages = filter(string pkg_name, minimal_packages, ``( ! contains(installed_packages, pkg_name )));
// fix Pkg bug. GetPackages get not the reinstalled_packages!!
// (seems to be fixed in 9.0 ...)
missing_packages = filter(string pkg_name, missing_packages, ``( ! contains( reinstalled_packages, pkg_name)));
boolean ret = size(missing_packages) == 0;
if (! ret )
{
y2error ("These packages belonging to the minimal selection were not found: %1", missing_packages);
// set information for repair dialog
install_missing_dialog_data = [
// headline
_("Missing Packages"),
// check for package minimum summary, 1st part (table follows)
_("
The following packages are
not installed."),
// check for package minimum summary, last part (below table)
_("
The listed packages belong to the minimal
package selection. Installing these
packages is recommended. Press
Repair to install all selected
packages in the list.
"),
// check for package minimum help text 1/2
_("
<P>&product; needs at least some packages for
basic system functionality. Without these
packages, the system is not executable.</P>
") +
// check for package minimum help text 2/2, %1 is tool name
sformat (_("<P>%1 checks if all required packages for a
minimal system are installed. If
some packages are missing, %1 offers to
install the missing packages.</P>
"), OSRCommon::tool_name),
// table headline (package list follows)
_("&Missing Packages to Install"),
[]
];
}
return ret;
};
/**
* Verify all specified packages.
* @param root The mount point where the target system is mounted.
* @param what "all" or "base" packages
* @param expert_mode Show the verify protocol too
* @param reset Clear missing_packages before start verifying.
*/
global define symbol VerifyPackages(string root, string what , boolean expert_mode, boolean reset )``{
if (Mode::test ())
return `next;
if (root != "" && root != nil )
{
root_mountpoint = root;
}
if (reset )
{
missing_packages = [];
}
// open package database
if (! OpenPkg(root_mountpoint) )
{
y2error("Opening the package database failed. Verify package not possible");
return `error;
}
if (! CheckProductVersions ())
{
return `different_products;
}
list<string> check_packages = toset(get_verify_packages(what));
if (check_packages == nil || size(check_packages) == 0 )
{
y2error("No packages to verify found. Stop verify and return error.");
return `error;
}
// dialog headline
string headline = ( what != "all" ) ? _("Verifying Base Packages") :
// dialog headline
_("Verifying All Installed Packages");
// open dialog
if (! OSRPkgUI::OpenVerifyDialog (size(check_packages), headline , expert_mode) )
{
y2error("Verify Dialog can not be opened");
return `error;
}
symbol ret = `again;
string rret = "";
repeat
{
// verify all selected packages
foreach(string p, check_packages, ``{
if (ret != `abort )
{
rret = (string) UI::PollInput();
if (! (rret == "" || rret == nil ))
{
ret = OSRPkgUI::EvalUserInput(rret );
if (ret == `abort ) return `abort;
if (ret == `pause )
{
repeat
{
y2milestone("Starting pause loop");
rret = (string) UI::UserInput();
ret = OSRPkgUI::EvalUserInput (rret);
if (ret == `abort )
return `abort;
} until (ret == `continue || ret == `abort ||
ret == `cancel);
}
}
if (! OSRPkgVerify::PackageVerified (p) &&
ret != `abort && ret != `cancel)
{
boolean ver = OSRPkgVerify::Verify (p, root_mountpoint);
OSRPkgUI::AddPackageSummary (p);
if (!ver )
{
missing_packages = add (missing_packages, p );
}
}
}
});
OSRPkgUI::Finish();
// finish verified wait for user input in expert mode.
if (ret != `abort && OSRPkgUI::expert_mode )
{
check_packages = [];
rret = (string) UI::UserInput();
y2milestone(" user input get signal %1", rret);
if (ret != nil ) // e.g.: get a `cancel or `abort
{
ret = OSRPkgUI::EvalUserInput( rret );
}
else {
ret = `next;
}
// all packages verified.
if (ret == `abort || ret == `cancel ) ret = `next;
}
// close dialog in normal mode
else {
ret = `next;
}
} until ( ret == `next || ret == `abort || ret == `cancel );
UI::CloseDialog();
missing_packages = OSRPkgVerify::not_successful_verified;
OSRPkgVerify::WriteVerifiedPackages( check_packages, false);
if (size( missing_packages ) > 0)
{
// button label
string protocol_label = _("Show Log");
OSRPkgUI::expert_mode = true;
install_missing_dialog_data = [
// dialog headline
_("Unverified Packages"),
// package verification summary, 1st part (table follows)
_("
Verified the installed software
and found problems in the following
packages.
"),
// package verification summary, last part
_("
These packages probably differ from their
originally installed versions. Check
the packages to reinstall and start
the reinstallation process by pressing
Repair.
"),
// package verification summary, help text (%1 is button label)
sformat (_("
<p>All installed packages have been verified. Some
of these packages contain errors. For details,
see the log of the verification process.
To open the log, press <b>%1</b>.</p>
"), protocol_label) +
// package verification summary 2/3
_("<p>There, see if files of the package are
missing or the data of the package in the package
database differs from the installed files of the
package.</P>") +
// package verification summary 3/3
_("<p>Sometimes, verification of the package could
report errors even if the package is correctly
installed and works fine. That is why you should
reinstall only the packages that do not work properly.</p>
"),
// table headline (package list follows)
_("Packages with Problems"),
[ [
`Right(`PushButton( `id(`protocol), protocol_label )),
`protocol, OSRPkgUI::ProtocolDialog
] ]
];
}
return ret;
}
/**
* Install selected Packages. The packages are damaged or not install.
* Call CheckMinimum or VerifyPackages before.
*/
global define symbol InstallMissing(boolean use_dialog )``{
symbol ret = `ok;
if (size(missing_packages) > 0 )
{
list<list> item_list = [];
foreach(string item, missing_packages, ``{
item_list = add( item_list, [item, false]);
});
item_list = OSRPkgUI::update_missing_packages (item_list, true);
if (use_dialog )
{
missing_packages = OSRPopup::MultiSelectionBox (
install_missing_dialog_data[0]:"",
install_missing_dialog_data[1]:"",
install_missing_dialog_data[2]:"",
install_missing_dialog_data[3]:"",
install_missing_dialog_data[4]:"",
item_list,
install_missing_dialog_data[5]:[]
);
}
if (missing_packages == [] )
{
y2milestone("No packages to install. User skiped reinstall.");
ret = `cancel;
}
else
{
y2milestone("Install missing or damaged packages %1", missing_packages );
if (OpenPkg(root_mountpoint ))
{
boolean ok = true;
foreach (string p, missing_packages , ``{
ok = ok && Pkg::PkgInstall (p);
if (! ok )
{
y2error("Change the state to install for package %1 failed", p );
}
});
ok = ok && Pkg::PkgSolve (false);
y2milestone("Solving dependencies returned %1", ok );
list result = Pkg::PkgCommit (0);
y2milestone ("PkgCommit: %1", result );
ok = ok && result[1]:nil == [] && result[2]:nil == [];
Wizard::CreateDialog ();
Wizard::SetTitleIcon("misc");
WFM::CallFunction ("inst_suseconfig", [false, false]);
Wizard::CloseDialog ();
if (ok)
{
reinstalled_packages = missing_packages;
y2milestone("All reinstalled_packages: %1",
reinstalled_packages );
ret = `ok;
}
else ret = `error;
}
else {
y2error("Opening the ppackage database failed");
ret = `error;
}
}
}
else {
y2error("No missing packages. Set missing_packages before.");
ret = `cancel;
}
return ret;
}
}//EOF