home *** CD-ROM | disk | FTP | other *** search
Text File | 2006-11-29 | 39.2 KB | 1,465 lines |
- /**
- * File: modules/SourceManager.ycp
- * Package: Package Source Management
- * Summary: SourceManager settings, input and output functions
- * Authors: Anas Nashif <nashif@suse.de>
- * Lukas Ocilka <locilka@suse.cz>
- * Martin Vidner <mvidner@suse.cz>
- * Status: Work in Progress
- *
- * $Id: SourceManager.ycp 34515 2006-11-21 09:20:08Z mvidner $
- *
- * Representation of the configuration of source-manager.
- * Input and output routines.
- */
-
- {
-
- textdomain "packager";
- module "SourceManager";
-
- import "Progress";
- import "Report";
- import "Popup";
- import "Label";
- import "Summary";
- import "Message";
- import "HTML";
- import "Arch";
- import "Mode";
- import "Stage";
- import "URL";
- import "InstURL";
- import "String";
- import "SuSEFirewall";
- import "SourceManagerSLP";
- import "Linuxrc";
-
-
- global list<integer> newSources = [];
-
- global integer numSources = 0;
-
- global list<integer> sourceStates = [];
-
- global list<map<string,any> > sourceStatesIn = [];
-
- global list<map<string,any> > sourceStatesOut = [];
-
-
- list<map> slp_sources = [];
-
- string pm_init_blocker = "";
-
- global map url_tokens = $[];
-
- global string currentUrl = "";
-
- /**
- * Prototypes
- */
- global boolean Modified();
- global symbol createSource( string url );
-
- /**
- * Data was modified?
- */
- global boolean modified = false;
-
- /**
- */
- global boolean proposal_valid = false;
-
- /**
- * Abort function
- * return boolean return true if abort
- */
- global boolean AbortFunction() {
- return false;
- }
-
- /**
- * Abort function
- * @return boolean return true if abort
- */
- global define boolean Abort() ``{
- if(AbortFunction != nil)
- {
- return AbortFunction () == true;
- }
- return false;
- }
-
- /**
- * Data was modified?
- * @return true if modified
- */
- global boolean Modified() {
- y2debug("modified=%1",modified);
- //return modified;
- return (sourceStatesIn != sourceStatesOut);
- }
-
- global boolean ReadSources()
- {
- boolean success = Pkg::SourceStartManager( false );
- if (!success)
- return success;
- sourceStates = Pkg::SourceStartCache ( false );
- sourceStatesIn = Pkg::SourceEditGet();
- sourceStatesOut = sourceStatesIn;
- return true;
- }
-
- /**
- * Function scans for SLP installation servers on the network
- * @returns symbol one of `back, `next
- */
- global string AddSourceTypeSLP () {
- string url = SourceManagerSLP::SelectOneSLPService();
- y2milestone("Selected URL: %1", url);
-
- return url;
- }
-
- /**
- * Read all source-manager settings
- * @return true on success
- */
- global boolean Read() {
-
- /* SourceManager read dialog caption */
- string caption = _("Initializing Available Catalogs");
-
- integer steps = 2;
-
-
- // We do not set help text here, because it was set outside
- Progress::New( caption, " ", steps, [
- /* Progress stage 1/3 */
- _("Read configured catalogs"),
- /* Progress stage 2/3 */
- _("Detect available catalogs via SLP")
- ], [
- /* Progress step 1/3 */
- _("Reading configured catalogs..."),
- /* Progress step 2/3 */
- _("Detecting available catalogs..."),
- /* Progress finished */
- _("Finished")
- ],
- ""
- );
-
- // read database
- if(Abort()) return false;
- Progress::NextStage();
-
-
- /* Error message */
- if(!ReadSources()) Report::Error(_("Cannot read catalogs."));
-
- // read another database
- if(Abort()) return false;
- Progress::NextStep();
-
-
- /* Error message */
- if(false) Report::Error(_("Cannot detect available catalogs."));
-
- if(Abort()) return false;
- /* Progress finished */
- Progress::NextStage();
-
- // slp_sources = ReadSLPSources();
-
- y2debug ("slp catalogs: %1", slp_sources);
-
- if(Abort()) return false;
- modified = false;
- return true;
- }
-
- /**
- * Commit changed sources
- */
- global boolean CommitSources() {
- y2debug("In: %1 Out: %2", sourceStatesIn, sourceStatesOut );
- boolean success = false;
- while (true)
- {
- success = Pkg::SourceEditSet( sourceStatesOut );
- if ( !success ) {
- // popup message header
- string _msg1 = _("Unable to save changes to the catalog
- repository.
- ");
- // popup message, after message header, header of details
- string _msg2 = _("Details:") + "\n" + Pkg::LastError();
- // end of popup message, question
- _msg2 = _msg2 + "\n" + _("Try again?");
-
- boolean tryagain = Popup::YesNo( _msg1 + "\n" + _msg2 );
- if (tryagain )
- continue;
- else
- break;
- }
- else
- {
- break;
- }
- }
- return success;
- }
-
- /**
- * Write all source-manager settings
- * @return true on success
- */
- global boolean Write() {
-
- /* SourceManager read dialog caption */
- string caption = _("Saving Catalog Configuration");
-
- integer steps = 1;
-
- // We do not set help text here, because it was set outside
- Progress::New(caption, " ", steps, [
- /* Progress stage 1/1 */
- _("Write catalog settings"),
- ], [
- /* Progress step 1/1 */
- _("Writing the settings..."),
-
- /* Progress finished */
- _("Finished")
- ],
- ""
- );
-
- // write settings
- if(Abort()) return false;
-
- Progress::NextStage();
- /* Error message */
-
- boolean exit = CommitSources();
-
-
-
- if(Abort()) return false;
- /* Progress finished */
- Progress::NextStage();
-
- if(Abort()) return false;
-
- return exit;
- }
-
- /**
- * Get all source-manager settings from the first parameter
- * (For use by autoinstallation.)
- * @param settings The YCP structure to be imported.
- * @return boolean True on success
- */
- global boolean Import (map settings) {
- return true;
- }
-
- /**
- * Dump the source-manager settings to a single map
- * (For use by autoinstallation.)
- * @return map Dumped settings (later acceptable by Import ())
- */
- global map Export () {
- return $[];
- }
-
-
-
-
- global boolean CreateLocalMetaData (
- integer SrcId,
- string metaDir,
- string slidedir,
- string descrDir,
- string prodDir) {
-
- boolean all_sources_ok=true;
- string localdir = metaDir+"/"+descrDir;
- WFM::Execute (.local.mkdir, localdir);
- y2debug("created local dir : %1", localdir );
- string datadir = Pkg::SourceProvideDir (SrcId, 1, descrDir+"/media.1");
- if (datadir != nil)
- {
- WFM::Execute (.local.mkdir, localdir+"/media.1");
- WFM::Execute (.local.bash, "/bin/cp " + datadir + "/* " + localdir+"/media.1");
- }
- else
- {
- y2error ("media doesn't provide %1", descrDir + "/media.1");
- if (Popup::AnyQuestion (
- // Popup::NoHeadline(),
- // popup headline
- _("Reading Media Description Failed"),
- sformat (
- // popup message, %1 is filename
- _("Cannot read media description for %1.
- Packages from this media cannot be installed."), descrDir),
- Label::IgnoreButton (),
- Label::AbortButton (),
- `cancel))
- {
- return false;
- }
- else
- {
- all_sources_ok = false;
- }
- }
-
- // content file
- datadir = Pkg::SourceProvideFile (SrcId, 1, descrDir+"/content");
- WFM::Execute (.local.bash, "/bin/cp " + datadir + " " + localdir + "/content");
-
- // DESCRDIR
- WFM::Execute (.local.bash, "/bin/grep DESCRDIR " + localdir + "/content > /tmp/descrdir");
- string descrline = (string) WFM::Read (.local.string, "/tmp/descrdir");
- list<string> descrsplit = splitstring (descrline, " \t\n");
- string _descrdir = descrsplit[1]:"";
- if (size (_descrdir) > 0)
- {
- y2milestone ("descrdir %1", _descrdir);
- WFM::Execute (.local.mkdir, localdir+"/"+_descrdir);
- datadir = Pkg::SourceProvideDir (SrcId, 1, descrDir+"/"+_descrdir);
- if (datadir != nil)
- {
- WFM::Execute (.local.bash, "/bin/cp " + datadir + "/* " +localdir+"/"+_descrdir);
- } else {
- y2error("Error providing %1", _descrdir );
- }
- }
-
- // copy GPG keys if there are any
-
- string directory_file = Pkg::SourceProvideFile (
- SrcId, 1, descrDir + "/directory.yast");
-
- string directory_str = (string)
- WFM::Read (.local.string, directory_file);
- list<string> directory = splitstring (directory_str, "\n");
- directory = filter (string d, directory, {
- return substring (d, 0, 10) == "gpg-pubkey";
- });
- y2milestone ("GPG keys to be copied: %1", directory);
- foreach (string k, directory, {
- string file = Pkg::SourceProvideFile (
- SrcId, 1, descrDir + "/" + k);
- WFM::Execute (.local.bash,
- "cp /" + file + " " + localdir);
- });
-
- // slide show
-
- if (size (_descrdir) > 5)
- {
- string tmp = substring (_descrdir, 0, size (_descrdir) - 5) + "slide";
- y2milestone("slide dir: %1", tmp );
- WFM::Execute (.local.mkdir, localdir+"/"+tmp);
- // FIXME: SourceProvideDir can't handle dirs with subdirs
- datadir = Pkg::SourceProvideDir (SrcId, 1, descrDir+"/"+tmp);
- // datadir = "/var/adm/YaST/InstSrcManager/IS_CACHE_0x00000001/MEDIA" + orderdir+"/"+tmp;
- y2milestone ("tmp=%1, datadir=%2", tmp, datadir);
- if (datadir != nil)
- {
- y2milestone ("copy slide show %1 %2", datadir, slidedir);
- WFM::Execute (.local.bash, "/bin/cp -r " + datadir + "/* " + slidedir);
-
- // if directory is empty, remove it.
- WFM::Execute (.local.bash, "/bin/rmdir " + slidedir);
- }
- }
-
- return all_sources_ok;
-
- }
-
-
- /**
- * Get Source ID by index
- */
- global integer GetSrcIdByIndex(integer idx) {
-
- integer SrcId = sourceStatesOut[idx, "SrcId"]:-1;
-
- return SrcId;
- }
-
- /**
- * Set current used source URL by index
- */
- global void SetUrlByIndex(integer idx) {
-
- integer SrcId = sourceStatesOut[idx, "SrcId"]:-1;
- currentUrl = Pkg::SourceGeneralData(SrcId)["url"]:"";
- return;
- }
-
-
- /**
- * Get Source ID when only URL is known
- */
- global define integer getSourceId( string url ) {
-
- numSources = size( sourceStatesOut );
- integer i = 0;
- integer id = -1;
- while ( i < numSources )
- {
- map generalData = Pkg::SourceGeneralData(sourceStatesOut[i, "SrcId"]:-1 );
- if ( generalData[ "url" ]:"" == url )
- {
- id = sourceStatesOut[i, "SrcId"]:-1;
- break;
- }
-
- i = i + 1;
- }
-
- return id;
- }
-
-
-
-
-
-
- /**
- * Gather Source Metadata
- */
- global define map SourceData(integer source) ``{
- map g = Pkg::SourceGeneralData( source );
- y2milestone("generalData: %1", g);
- map p = Pkg::SourceProductData( source );
- if (p == nil)
- {
- p = $[];
- }
-
- y2milestone("productData: %1", p);
- return ((map)union(g,p));
- }
-
- /**
- * Create a Source from an URL
- */
- global symbol createSource( string url ) {
-
- if ( url != "" )
- {
- if (!Mode::commandline())
- {
- // Popup::Message( sformat( "URL: %1", url ) );
- UI::OpenDialog(
- `VBox(
- `VSpacing( 0.2 ),
- `Label( _("Adding catalog...") ),
- `VSpacing( 0.2 )
- )
- );
- }
- newSources = Pkg::SourceScan( url, "" );
-
- if (!Mode::commandline())
- UI::CloseDialog();
-
-
- if ( size( newSources ) == 0 )
- {
- string _msg1 = sformat( _("Unable to create catalog
- from URL '%1'."), InstURL::HidePassword(url) );
-
- string _msg2 = _("Details:") + "\n" + Pkg::LastError();
- // end of popup message, question
- _msg2 = _msg2 + "\n" + _("Try again?");
-
- boolean tryagain = Popup::YesNo( _msg1 + "\n" + _msg2 );
- if ( tryagain ) return `again;
- else return `cancel;
- }
- else
- {
- list<integer> ul_sources = filter (integer s, newSources, {
- map src_data = Pkg::SourceGeneralData (s);
- string src_type = src_data["type"]:"";
- return src_type == "YaST";
- });
- if (size (ul_sources) == 0)
- {
- if (! Popup::AnyQuestion (
- Popup::NoHeadline (),
- // continue-back popup
- _("There is no product information available at the given location.
- If you expected to address a product, return back and enter
- the correct location.
- To make rpm packages located at the specified location available
- in the packages selection, continue."),
- Label::ContinueButton (),
- Label::BackButton (),
- `focus_yes))
- {
- return `again;
- }
- }
- foreach( integer id, newSources, ``{
- map<string, any> sourceState = $[ "SrcId": id, "enabled": true ];
- sourceStatesOut = add( sourceStatesOut, sourceState );
- } );
- return `ok;
- }
- }
- return `cancel;
- }
-
- /**
- * Delete Source by Source ID
- */
- global void deleteSourceBySrcId( integer SrcId ) {
-
- y2debug("removing source: %1 %2", SrcId, sourceStatesOut );
- numSources = size( sourceStatesOut );
- integer i = 0;
-
- while ( i < numSources )
- {
-
- if ( sourceStatesOut[i, "SrcId"]:-1 == SrcId )
- {
- sourceStatesOut = remove( sourceStatesOut, i );
- break;
- }
-
- i = i + 1;
- }
- return;
-
- }
-
-
- /**
- * Delete Source by Source Index
- */
- global void deleteSourceByIndex (integer idx ) {
-
- sourceStatesOut = remove( sourceStatesOut, idx );
- return;
- }
-
- /**
- * Delete Source by Source URL
- */
- global void deleteSourceByUrl (string url ) {
- deleteSourceBySrcId(getSourceId(url));
- return;
- }
-
- /**
- * Create Summary Item
- */
- define string createItem( integer index, map source ) {
- integer id = source[ "SrcId" ]:0;
- map generalData = Pkg::SourceGeneralData( id );
- map productData = Pkg::SourceProductData( id );
- string sitem = "";
- string status = source[ "enabled" ]:true
- // status info, to be used inside summary
- ? _("Enabled")
- // status info, to be used inside summary
- : _("Disabled");
- string color = source[ "enabled" ]:true ? "#006600" : "#FF0000";
- sitem = sitem + HTML::Colorize("["+status+"] ",
- color);
- // translators: name of a source if no other idenfication found
- sitem = sitem + productData[ "label" ]:generalData["type"]:_("unknown");
- sitem = sitem + " ( " + generalData[ "url" ]:"" + ")";
- return sitem;
- }
-
-
- /**
- * Create Source Item for Overview
- */
- define term createOverviewItem( integer index, map source ) {
- integer id = source[ "SrcId" ]:0;
- map generalData = Pkg::SourceGeneralData( id );
- map productData = Pkg::SourceProductData( id );
-
-
- term item = `item(
- `id(index ),
- source[ "enabled" ]:true
- // corresponds to the "Enable/Disable" button
- ? _("On")
- // corresponds to the "Enable/Disable" button
- : _("Off"),
- productData[ "label" ]:generalData["type"]:_("Unknown"),
- generalData[ "url" ]:""
- );
-
- return item;
- }
-
-
- /**
- * Handle Multiple source URLs (order/instorder)
- */
- boolean HandleMultipleSources( string url ) {
-
- boolean metadir_used = false;
- list<string> theSourceDirectories = [];
- map<integer,integer> theSourceOrder = $[];
-
- list theSources=[];
- string tmpdir = (string) SCR::Read(.target.tmpdir );
- string metadir = tmpdir + "/yast-install";
-
-
- Pkg::SourceStartManager( false );
- integer initial_source = Pkg::SourceScan(url, "")[0]:nil;
- if (initial_source == nil)
- {
- y2error ("No source on '%1'", url);
- return false;
- }
-
- return false;
- }
-
-
- /**
- * Create a textual summary and a list of unconfigured cards
- * @return summary of the current configuration
- */
- global list Summary() {
-
- string summary = "";
- // summary header
- summary = Summary::AddHeader(summary, _("Configured Catalogs"));
- summary = Summary::OpenList(summary);
- numSources = size( sourceStatesOut );
- integer i = 0;
- while ( i < numSources ) {
- summary = Summary::AddListItem(summary,createItem(i, sourceStatesOut[ i ]:$[]));
- i = i + 1;
- }
- summary = Summary::CloseList(summary);
-
-
-
- list unconf = maplist(map s, slp_sources, ``{
- string id = substring(s["srvurl"]:"", 21);
- y2debug("source url : %1", id );
- // part of item in summary
- return(`item(`id(id), s["attr", "label"]:_("Unknown")
- // part of item in summary meaning "switched on"
- + _(" On ") + s["pcHost"]:""));
- });
-
- return [summary, unconf ];
- }
-
- /**
- * Create an overview table with all configured cards
- * @return table items
- */
- global list Overview() {
- numSources = size( sourceStatesOut );
- integer i = 0;
- list source_overview = [];
- while ( i < numSources ) {
- source_overview = add(source_overview,
- createOverviewItem(i, sourceStatesOut[ i ]:$[] ));
- i = i + 1;
- }
- return source_overview;
- }
-
- // ------------------------------------------------------------------------------------------------------
- // adding YaST installation source into the ZMD
-
- global string SyncLabel () {
- // yast is running a zenworks command (rug) to
- // keep the repository references in sync
- return _("Synchronizing with ZENworks");
- }
-
- /**
- * Runs a bash command with timeout.
- * @struct Returns map $[
- * "exit" : int_return_code,
- * "stdout" : [ "script", "stdout", "lines" ],
- * "stderr" : [ "script", "stderr", "lines" ],
- * ]
- *
- * @param run_command what to run
- * @param log_command what to log (passwords masked)
- * @param script_time_out in sec.
- * @return map with out, err and ret_code
- */
- global map RunCommandWithTimeout (string run_command, string log_command, integer script_time_out) {
- y2milestone("Running command \"%1\" in background...", log_command);
-
- boolean started = (boolean) SCR::Execute(.background.run_output_err, run_command);
- if (!started) {
- y2error("Cannot run '%1'", run_command);
- return nil;
- }
-
- list<string> script_out = [];
- list<string> script_err = [];
- integer time_spent = 0;
- integer return_code = nil;
- boolean timed_out = false;
- integer sleep_step = 200; // ms
- script_time_out = script_time_out * 1000;
-
- // while continuing is needed and while it is possible
- while (! timed_out) {
- boolean running = (boolean) SCR::Read(.background.isrunning);
- // debugging #165821
- if (time_spent % 100000 == 0) {
- y2milestone ("running: %1", running);
- string flag = "/tmp/SourceManagerTimeout";
- if (SCR::Read (.target.size, flag) != -1) {
- y2milestone ("Emergency exit");
- SCR::Execute (.target.remove, flag);
- break;
- }
- }
-
- if (! running) {
- break;
- }
-
- // at last, enable aborting the sync
- if (Mode::commandline ()) {
- sleep (sleep_step);
- }
- else {
- any ui = UI::TimeoutUserInput (sleep_step);
- if (ui == `abort) {
- y2milestone ("aborted");
- timed_out = true;
- break;
- }
- }
-
- // time-out
- if (time_spent >= script_time_out) {
- y2error("Command timed out after %1 msec", time_spent);
- timed_out = true;
- }
-
- time_spent = time_spent + sleep_step;
- }
- y2milestone("Time spent: %1 msec", time_spent);
-
- // fetching the return code if not timed-out
- if (! timed_out) {
- y2milestone ("getting output");
- script_out = (list<string>) SCR::Read(.background.newout);
- y2milestone ("getting errors");
- script_err = (list<string>) SCR::Read(.background.newerr);
- y2milestone ("getting status");
- return_code = (integer) SCR::Read(.background.status);
- }
- y2milestone ("killing");
- SCR::Execute(.background.kill, "");
-
- map command_ret = $[
- "exit" : return_code,
- "stdout" : script_out,
- "stderr" : script_err,
- ];
- if (timed_out)
- command_ret["timed_out"] = time_spent;
- return command_ret;
- }
-
- /**
- * Run
- * - with a timeout
- * - on dumb terminal to disable colors etc
- * - using 'exit $?' because of buggy behavior '.background vs. ZMD'
- * @param command a command
- * @param log_command a command to log
- * @param seconds timeout
- * @return map with out, err and ret_code
- */
- global map RunDumbTimeout (string command, string log_command, integer seconds) {
- string dumb_format = "export TERM=dumb; %1; exit $?";
- string dumb_command = sformat (dumb_format, command);
- string dumb_log_command = sformat (dumb_format, log_command);
- // explicit export in case TERM was not in the environment
- map ret = RunCommandWithTimeout (dumb_command, dumb_log_command, seconds);
- if (ret == nil) ret = $[];
- return ret;
- }
-
- /**
- * Run with a long timeout
- * @param command a command
- * @param log_command a command to log
- * @return map with out, err and ret_code
- */
- map RunLongLog (string command, string log_command) {
- return RunDumbTimeout (command, log_command, 1800);
- }
-
- /**
- * Run with a long timeout
- * @param command a command
- * @return map with out, err and ret_code
- */
- map RunLong (string command) {
- return RunLongLog (command, command);
- }
-
- /**
- * path to ZMD CLI
- */
- const string rug = "/usr/bin/rug";
-
- /**
- * Detect whether ZMD is running
- */
- boolean CheckZMDStatus () {
- map zmd_status = RunLong (rug + " ping >/dev/null");
- y2milestone("ZMD status: %1, err: %2", zmd_status["exit"]:nil, zmd_status["stderr"]:[]);
- // Argh zis suks so mutch! #170549
- return zmd_status["exit"]:nil == 0 || zmd_status["stderr"]:[] == [];
- }
-
- list<string> known_urls = nil;
-
- /**
- * Force calling rug on next @ref IsUrlKnownToZMD
- */
- void ResetKnownServiceCache () {
- known_urls = nil;
- }
-
- /**
- * Update the cache after a successful rug service-{add,delete} call
- * @param adding add url or delete it
- * @param url what
- */
- void UpdateKnownServiceCache (boolean adding, string url) {
- if (adding) {
- known_urls = add (known_urls, url);
- } else {
- known_urls = filter (string u, known_urls, ``( u != url ));
- }
- }
-
- /**
- * Whether the URL is known to rug service-list.
- * The known services are cached,
- * the caller should use @ref ResetKnownServiceCache if appropriate
- * (each time when coming from outside this module at least)
- * @return boolean or nil if determining the status failed
- */
- boolean IsUrlKnownToZMD (string url) {
- if (known_urls == nil)
- {
- //format: "3|Active|ZYPP|ServiceName|ftp://example.org/update/10.1"
- // With empty lines and "Waking up ZMD...Done" as a distraction
- map ret = RunLong (rug + " --no-abbrev --terse service-list | cut -d'|' -f5 --only-delimited");
- if (ret["stdout"]:nil == nil) {
- y2error("Listing of services failed, returned %1", ret);
- return nil;
- }
- // really individual lines?
- known_urls = (list <string>) ret["stdout"]:[];
- list<string> log_known_urls = maplist (string u, known_urls, ``(
- InstURL::HidePassword(u)
- ));
- y2milestone ("known %1", log_known_urls);
- }
- return contains (known_urls, url);
- }
-
- /**
- * Get a ZMD preference
- * @param pref see "rug get-prefs"
- */
- string RugGetPref (string pref) {
- // "pref|value"
- map ret = RunLong (sformat ("%1 --terse get-prefs %2 | cut -d'|' -f2 --only-delimited", rug, pref));
- if (ret["stdout"]:nil == nil) {
- y2error("GetPref failed, returned %1", ret);
- return nil;
- }
- string line = ret["stdout", 0]:"";
- return deletechars (line, "\n");
- }
-
- /**
- * Set a ZMD preference
- */
- void RugSetPref (string pref, string value) {
- map ret = RunLong (sformat ("%1 set-prefs %2 '%3'", rug, pref, value));
- y2milestone ("ret %1", ret);
- }
-
- /**
- * Adds a ZYPP service into ZMD
- * @param src_id installation source id
- * @return success
- */
- boolean AddOrDeleteZYPPServiceIntoZMD (integer src_id, boolean adding) {
- map gendata = Pkg::SourceGeneralData (src_id);
- string stype = gendata["type"]:""; // metadata type
- if (stype == "YaST") stype = "zypp"; /* 'rug' only accepts yum or zypp */
- string url = gendata["url"]:"";
- string log_url = InstURL::HidePassword (url);
- // ZMD must have unique URIs, so we append the alias
- string alias = gendata["alias"]:"";
- y2milestone ("id: %1, type: %2, url: %3, alias: %4", src_id, stype, log_url, alias);
- if (stype == "" || url == "" || alias == "") {
- y2error ("Internal error: stype, url, or alias is empty ?!");
- return false;
- }
-
- // yum sources do not need+understand the alias, #164083
- // The above reason is obsolete but we keep compatibility with
- // the service-delete zmd helper
- if (stype == "zypp")
- {
- // URL (un)escapes for us
- // maybe a bug with "="?
- map parsed_url = URL::Parse (url);
- string query = parsed_url["query"]:"";
- if (query != "") query = query + "&";
- parsed_url["query"] = query + "alias=" + alias;
- string test_url = URL::Build (parsed_url);
- y2milestone ("test zmd url: %1", InstURL::HidePassword(test_url));
-
- string separator = (search (url, "?") == nil)? "?": "&";
- url = url + separator + "alias=" + alias;
- }
- log_url = InstURL::HidePassword (url);
- y2milestone ("zmd url: %1", log_url);
-
- // we're done if known and adding or unknown and deleting.
- // if the status is uncertain (error),
- // we proceed to be able to report it
- boolean done_already = adding == IsUrlKnownToZMD (url);
- if (done_already) {
- y2milestone ("already in sync");
- return true;
- }
-
- string name = alias;
- string owner = "zypp"; // not stype: #168739
-
- string command = nil;
- string log_command = nil;
- // be quiet, #179080
- if (adding) {
- const string format = "%4 --quiet service-add --type='%3' '%1' '%2' && %4 subscribe '%1'";
- command = sformat (format, url, name, owner, rug);
- log_command = sformat (format, log_url, name, owner, rug);
- }
- else {
- const string format = "%2 --quiet service-delete '%1'";
- command = sformat (format, url, rug);
- log_command = sformat (format, log_url, rug);
- }
- map ret = RunLongLog (command, log_command); // #165145
- if (ret["exit"]:nil == 0) {
- UpdateKnownServiceCache (adding, url);
- return true;
- } else {
- string message = adding?
- // rug is a command name
- _("Your service was added successfully in YaST, but could not be synchronized with ZenWorks."):
- _("Your service was deleted successfully in YaST, but could not be synchronized with ZenWorks.");
- message = message + ":";
- if (ret["stdout"]:[] != [])
- message = message + "\n" + mergestring (ret["stdout"]:[], "\n");
- if (ret["stderr"]:[] != [])
- message = message + "\n" + mergestring (ret["stderr"]:[], "\n");
- else if (haskey (ret, "timed_out"))
- // error message
- // FIXME "ms" or plural gettext
- message = message + "\n" + sformat (_("Command timed out after %1 milliseconds."), ret["timed_out"]:1000);
- Report::LongError (message);
- return false;
- }
- }
-
- /* ZMD service name - used for starting and stopping ZMD */
- string zmd_service_name = "/etc/init.d/novell-zmd";
-
- /**
- * Start ZMD if it was not running
- * Report::Error on failure
- * @return an opaque handle
- */
- map ZMDStart () {
- map zmd_handle = $[];
- // #214588: don't complain if it is not installed
- boolean installed = (integer) SCR::Read (.target.size, zmd_service_name) > 0;
- if (! installed) {
- y2milestone ("ZMD is not installed");
- return $[ "was_running": false, "is_running": false ];
- }
-
- boolean running = CheckZMDStatus ();
- zmd_handle ["was_running"] = running;
- if (! running) {
- // Starting the service
- map zmd_start = RunLong (zmd_service_name + " start");
- y2milestone("ZMD start: %1", zmd_start);
- }
- // Checking the status after start
- running = CheckZMDStatus ();
- zmd_handle ["is_running"] = running;
- if (! running) {
- Report::Error(Message::CannotStartService(zmd_service_name));
- }
- return zmd_handle;
- }
-
-
- /**
- * @param zmd_handle what ZMDStart returned
- * @return can we work with ZMD now
- */
- boolean ZMDWorking (map zmd_handle) {
- return zmd_handle["is_running"]:false;
- }
-
- /**
- * Restore the status before ZMDStart
- * Report::Error on failure
- * @param zmd_handle what ZMDStart returned
- */
- void ZMDRestore (map zmd_handle) {
- // It was running, nothing to change
- if (zmd_handle["was_running"]:false)
- return;
-
- if (zmd_handle["is_running"]:false)
- {
- y2milestone("Stopping service ZMD %1", zmd_service_name);
- map zmd_stop = RunLong (zmd_service_name + " stop");
- y2milestone("ZMD stop: %1", zmd_stop);
- // #166900, if stop fails it means it is still busy and
- // will stop later
- if (false && zmd_stop["exit"]:nil != 0) {
- Report::Error(Message::CannotStopService(zmd_service_name));
- }
- }
- y2milestone("ZMD stopped");
- }
-
- integer source_locked = 0;
- const string source_lock_flag = "/var/lib/zypp/sources-being-processed-by-yast";
- /**
- * Start a section where other processes (such as ZMD helpers) should not
- * access the source database. #170113
- * The calls may be nested.
- */
- global void Lock () {
- if (source_locked == 0)
- {
- SCR::Write (.target.string, source_lock_flag, "bug 170113");
- }
- source_locked = source_locked + 1;
- y2milestone ("lock: %1", source_locked);
- }
-
- /**
- * Other processes may access the source database again
- */
- global void Unlock () {
- source_locked = source_locked - 1;
- if (source_locked < 0)
- {
- y2internal ("Too many unlocks!");
- source_locked = 0;
- }
- if (source_locked == 0)
- {
- SCR::Execute (.target.remove, source_lock_flag);
- }
- y2milestone ("unlock: %1", source_locked);
- }
-
-
- /**
- * Checks whether ZMD is running, starts it when isn't. Checks whether a ZYPP source is listed
- * in the ZMD services, adds one if it is missing.
- * Everything is done via the .background agent with timeout (number in seconds).
- *
- * @return boolean whether the syncing succeeds
- */
- global boolean SyncYaSTInstSourceWithZMD () {
- // Notes for maintainer:
- // - using .background agent because of ZMD/rug call that can stuck
- // - using 'exit $?' that work well with ZMD/rug and .background together
- // - using TERM=dumb to suppress colors, progress bars etc. from ZMD/rug
- // - when the function finishes, it must leave ZMD in the same status (running/stopped)
- // as it was when the function started
- //
- // WARNIG: this function starts ZMD and expects that LIBZYPP has no lock over
- // the RPM database. You can run it only when the RPM is not locked
- // otherwise the ZMD will block itself!
-
- UI::OpenDialog (`VBox (
- // popup progress information
- `Label(SyncLabel ()), // #221250
- `PushButton (`id (`abort), Label::AbortButton ())
- ));
- y2milestone("--- Syncing YaST inst source with ZMD ---");
-
- Lock ();
-
- boolean ret = false;
- // Check the ZMD status and start if not running
- // If the ZMD wasn't running, we will try to start it
- // and then we will have to stop it at the end
- map zmd_handle = ZMDStart ();
- if (ZMDWorking (zmd_handle)) {
- // now we can work
-
- if (true) {
- string zmd_security_level = RugGetPref ("security-level");
- // The user has already decided to trust the inst sources
- // otherwise we would not be here. Do not ask again.
- // #182747
- RugSetPref ("security-level", "none");
-
- list<integer> src_ids = Pkg::SourceGetCurrent (false /*also disabled*/);
- ResetKnownServiceCache ();
- boolean added_ok = true;
- foreach (integer src_id, src_ids, {
- map gendata = Pkg::SourceGeneralData (src_id);
- // #219414, delete disabled ones (previous product version)
- boolean add_or_del = gendata["enabled"]:true;
- added_ok = AddOrDeleteZYPPServiceIntoZMD (src_id, add_or_del) && added_ok;
- });
- if (added_ok) {
- y2milestone("Adding ZYPP service succeeded");
- } else {
- Report::Error(Message::CannotWriteSettingsTo("ZMD"));
- y2error("Adding ZYPP service failed");
- }
- ret = added_ok;
-
- // restore
- if (zmd_security_level != nil)
- {
- RugSetPref ("security-level", zmd_security_level);
- }
- }
- }
- ZMDRestore (zmd_handle);
-
- Unlock ();
-
- y2milestone("--- Syncing finished ---");
- UI::CloseDialog();
- return ret;
- }
-
- /**
- * Sync the changed sources to ZenWorks
- * @param added_src_ids ids of sources that were added
- * @param deleted_src_ids ids of sources that were deleted
- * @return success
- */
- global boolean SyncAddedAndDeleted (list<integer> added_src_ids,
- list<integer> deleted_src_ids) {
- boolean ret = false;
- Lock ();
- map zmd_handle = ZMDStart ();
- if (ZMDWorking (zmd_handle)) {
- ret = true;
- ResetKnownServiceCache ();
-
- string zmd_security_level = RugGetPref ("security-level");
- RugSetPref ("security-level", "none"); // #190403
-
- // first delete, then add,
- // otherwise replacing a source with itself fails: #175159
- foreach (integer id, deleted_src_ids, {
- ret = AddOrDeleteZYPPServiceIntoZMD (id, false) && ret;
- });
- foreach (integer id, added_src_ids, {
- ret = AddOrDeleteZYPPServiceIntoZMD (id, true) && ret;
- });
-
- if (zmd_security_level != nil)
- {
- RugSetPref ("security-level", zmd_security_level);
- }
- }
- ZMDRestore (zmd_handle);
- Unlock ();
- return ret;
- }
-
- /**
- * Parse a URL query (already unescaped) to a map.
- * If no equal sign, the value will be nil.
- * @param query foo=bar&baz=qux
- * @return $["foo": "bar", "baz": "qux"]
- */
- map<string, string> ParseUrlQuery (string query) {
- list<string> q_items = splitstring (query, "&");
- map<string, string> q_map = listmap (string q_item, q_items, {
- integer eqpos = search (q_item, "=");
- if (eqpos == nil)
- {
- return $[ q_item: nil ];
- }
- else
- {
- string key = substring (q_item, 0, eqpos);
- string val = substring (q_item, eqpos + 1);
- return $[ key: val ];
- }
- });
- return q_map;
- }
-
- /**
- * @param attr SourceGeneralData item
- * @return For existing sources, get a mapping from an attribute to the id
- */
- map<string,integer> get_attr_to_id (string attr) {
- list<integer> src_ids = Pkg::SourceGetCurrent (false/*enabled only?*/);
- map<string,integer> a2i = listmap (integer src_id, src_ids, {
- map gendata = Pkg::SourceGeneralData (src_id);
- string alias = gendata[attr]:"";
- return $[ alias: src_id ];
- });
- return a2i;
- }
-
- /**
- * @return For existing sources, get a mapping from the alias to the id
- */
- map<string,integer> get_alias_to_id () {
- return get_attr_to_id ("alias");
- }
-
- /**
- * @return For existing sources, get a mapping from the URL to the id
- */
- map<string,integer> get_url_to_id () {
- return get_attr_to_id ("url");
- }
-
- /**
- * Extract an alias parameter from the URL and check whether we have
- * such a source already.
- * @param url a source with an alias parameter (actually optional)
- * @param alias_to_id a premade mapping, @see get_alias_to_id
- * @return the source id or -1
- */
- integer SourceByAliasOrUrl (string url,
- map<string,integer> alias_to_id,
- map<string,integer> url_to_id) {
- // parse the URL
- map parsed_url = URL::Parse (url);
- y2milestone ("parsed: %1", parsed_url);
- // (reassemble and warn if it differs)
- string reassembled = URL::Build (parsed_url);
- if (url != reassembled)
- {
- y2warning ("reassembled differs: %1", reassembled);
- }
- // get the alias
- map<string, string> q_map = ParseUrlQuery (parsed_url["query"]:"");
- y2milestone ("query: %1", q_map);
- string alias = q_map["alias"]:"";
-
- // (empty: box safeguard)
- if (alias != "" && haskey (alias_to_id, alias))
- {
- return alias_to_id[alias]:-1;
- }
- // #188572: if no match by alias, try url
- return url_to_id[url]:-1;
- }
-
- /**
- * Used by registration.
- * This is really hairy because we simultaneously add them to zypp and
- * zenworks, but not if they are not signed. (thus being better than
- * inst_source)
- * @param urls update sources to add
- * @return a list of added URLs
- */
- global list<string> AddUpdateSources (list<string> urls) {
- list<string> ret = [];
-
- // prepare for lookup of known aliases
- map<string,integer> aliases = get_alias_to_id ();
- y2milestone ("alias mapping: %1", aliases);
- map<string,integer> by_url = get_url_to_id ();
- y2milestone ("url mapping: %1", by_url);
-
- Lock ();
- map zmd_handle = ZMDStart ();
- boolean zmd_working = ZMDWorking (zmd_handle);
-
- ResetKnownServiceCache ();
-
- // add the sources.
- // but do not make duplicates (#168740)
- // we detect them based on alias that suse_register gives us (#158850#c17)
- /// (but only for SLE... :-/ )
- /// Need to test what happens when we get two different update
- /// servers for SL
- /// Anyway that means only that #168740 remains unfixed for SL
- foreach (string url, urls, {
- // #180820
- boolean is_nu = search (url, "$RCE") != nil;
- y2milestone ("Should add an update source: %1", url);
- // inst_addon_update_sources also calls Pkg::SourceCreate
- // but it already skips duplicates
-
- // check if alias already there
- // if yes, delete the old one
- integer todel = SourceByAliasOrUrl (url, aliases, by_url);
- if (todel != -1)
- {
- y2milestone ("deleting the old copy, source %1", todel);
- if (!is_nu && zmd_working)
- {
- AddOrDeleteZYPPServiceIntoZMD (todel, false);
- }
- Pkg::SourceDelete (todel);
- }
- // then add the new one
- y2milestone ("adding source");
- integer toadd = Pkg::SourceCreate (url, "/");
- // and add to zenworks too, but only if it succeeded here (#180820)
- if (toadd != -1 && toadd != nil)
- {
- ret = add (ret, url); // #180820#c26
- if (!is_nu && zmd_working)
- {
- AddOrDeleteZYPPServiceIntoZMD (toadd, true);
- }
- }
- });
-
- ZMDRestore (zmd_handle);
- Unlock ();
-
- return ret;
- }
-
- // adding YaST installation source into the ZMD
- // ------------------------------------------------------------------------------------------------------
-
- /**
- *
- */
- global boolean AskForCD (string message) {
- list<map<string,any> > cdroms = (list<map<string,any> >)
- SCR::Read (.probe.cdrom);
- boolean multiple_drives = size (cdroms) > 1;
- term drives_sel = `Empty ();
- list<string> devices = maplist (map<string,any> d, cdroms, {
- return d["dev_name"]:"";
- });
- if (multiple_drives)
- {
- drives_sel = `SelectionBox (`id (`drives), _("&Drive to eject"),
- devices);
- }
- term contents = `HBox (`HSpacing (1), `VBox (
- `VSpacing (0.5),
- `Label (message),
- `VSpacing (0.5),
- drives_sel,
- `VSpacing (0.5),
- `HBox (
- `HStretch (),
- `HWeight (1, `PushButton (`id (`cont), Label::ContinueButton ())),
- `HWeight (1, `PushButton (`id (`cancel), Label::CancelButton ())),
- `HWeight (1, `PushButton (`id (`eject), _("&Eject"))),
- `HStretch ()
- ),
- `VSpacing (0.5)
- ), `HSpacing (1));
- UI::OpenDialog (contents);
- if (multiple_drives)
- UI::ChangeWidget (`id (`drives), `CurrentItem, devices[0]:"");
- UI::SetFocus (`id (`cont));
- symbol ret = nil;
- while (true)
- {
- ret = (symbol)UI::UserInput ();
- if (ret == `cont || ret == `cancel)
- {
- break;
- }
- if (ret == `eject)
- {
- if (multiple_drives)
- {
- string device = (string)UI::QueryWidget (`id (`drives), `Value);
- SCR::Execute (.target.bash, sformat ("/bin/eject %1", device));
- }
- else
- {
- SCR::Execute (.target.bash, sformat ("/bin/eject %1",
- devices[0]:""));
- }
- }
- ret = nil;
- }
- UI::CloseDialog ();
- return ret == `cont;
- }
-
- /**
- * Function returns the partiton name which is used as a source for the installation
- * (IF any partition is used as a source for installation, of course).
- * Otherwise it returns an empty string "". See bugzilla #208222 for more information.
- *
- * @return string partition name
- */
- global string InstallationSourceOnPartition () {
- string install_mode = Linuxrc::InstallInf ("InstMode");
-
- // Hard Disk is used for the installation
- if (install_mode == "hd") {
- string install_partition = Linuxrc::InstallInf ("Partition");
-
- // No partiton is defined - error
- if (install_partition == "" || install_partition == nil) {
- y2error ("Despite the fact that the install-mode is '%1', install-partition is '%2'",
- install_mode, install_partition
- );
- return "";
- } else {
- return install_partition;
- }
- } else {
- return "";
- }
- }
-
- /* EOF */
- }
-