ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/Update.ycp

/**
 * Module:		Update.ycp
 *
 * Authors:		Anas Nashif <nashif@suse.de>
 *			Arvin Schnell <arvin@suse.de>
 *			Lukas Ocilka <locilka@suse.cz>
 *
 * Purpose:		Update module
 *
 * $Id: Update.ycp 51421 2008-09-23 15:24:33Z locilka $
 */
{
    module "Update";

    textdomain "update";

    import "Installation";
    import "Packages";
    import "ProductFeatures";
    import "ProductControl";
    import "Stage";
    import "SuSERelease";
    import "Mode";

    // number of packages to install
    global integer packages_to_install = 0;

    // number of packages to update
    global integer packages_to_update = 0;

    // number of packages to remove
    global integer packages_to_remove = 0;

    // number of packages unknown (problematic) by update
    global integer unknown_packages = 0;

    // number of errors (packages?) returned by solver
    global integer solve_errors = 0;

//    // Flag is set true if the user decides to delete unmaintained packages
//    global boolean deleteOldPackages = nil;

    // Flag is set to true when package downgrade is allowed
    global boolean silentlyDowngradePackages = nil;
	
    // Flag is set to true if installed packages should be kept
    global boolean keepInstalledPatches = nil;

    // don't allow upgrade only update
    global boolean disallow_upgrade = false;

    global boolean did_init1 = false;

    global boolean did_init2 = false;

    global integer last_runlevel = -1;

    // Only an update, NOT an upgrade
    global boolean onlyUpdateInstalled = nil;

    global string selected_selection = "";

    global boolean products_incompatible = false;

    // Version of the targetsystem
    //
    // !!! moved to Installation::installedVersion !!!
    //
    // global map <string, any> installedVersion = $[];

    // Version of the source medium
    //
    // !!! moved to Installation::updateVersion !!!
    //
    // global map <string, any> updateVersion = $[];


    // Flag, if the basesystem have to be installed
    global boolean updateBasePackages = false;

    // counter for installed packages
    global integer packagesInstalled = 0;


    // see bug #40358
    global boolean manual_interaction = false;

    // are the products (installed and to update) compatible?
    boolean _products_compatible = nil;

    /*-----------------------------------------------------------------------
     * FATE #301844 - Tuning Update Features
     *-----------------------------------------------------------------------*/

    boolean ListOfRegexpsMatchesProduct (list <string> regexp_items, string product) {
	if (regexp_items == nil || regexp_items == []) return false;
	if (product == nil) {
	    y2error ("Product is nil");
	    return false;
	}
	
	boolean ret = false;
	foreach (string one_regexp, regexp_items, {
	    if (regexpmatch (product, one_regexp)) {
		y2milestone (">%1< is matching >%2<", product, one_regexp);
		ret = true;
		break;
	    }
	});
	
	y2milestone ("Returning %1", ret);
	return ret;
    }

    /**
     * Returns whether old packages should be removed (defined in control file).
     * True means - delete old RPMs when updating. (Functionality for FATE #301844).
     */
/*
    // not supported by libzypp anymore

    global boolean DeleteOldPackages () {
	// changes deleteOldPackages variable
	any default_dop_a = ProductFeatures::GetFeature ("software", "delete_old_packages");

	boolean default_dop = nil;
	if (default_dop_a == nil || default_dop_a == "") {
	    y2error ("software/delete_old_packages not defined");
	    return false;
	}
	if (is (default_dop_a, boolean)) default_dop = (boolean) default_dop_a;

	string installed_system = SuSERelease::ReleaseInformation (Installation::destdir);
	y2milestone ("Processing '%1' from '%2'", installed_system, Installation::destdir);

	if (installed_system == nil || installed_system == "") {
	    y2error ("Cannot find out installed system name");
	    return default_dop;
	}
	
	any reverse_dop_a = ProductFeatures::GetFeature ("software", "delete_old_packages_reverse_list");
	// No reverse rules defined
	if (reverse_dop_a == "") {
	    return default_dop;
	}
	// not a list or empty list
	list <string> reverse_dop = (list <string>) reverse_dop_a;
	if (reverse_dop == nil || reverse_dop == []) return default_dop;

	if (ListOfRegexpsMatchesProduct (reverse_dop, installed_system)) {
	    return (! default_dop);
	}

	return default_dop;
    }
*/
    
    /**
     * Returns whether upgrade process should only update installed packages or
     * also install new packages. True means - do not upgrade, only update packages.
     * (Functionality for FATE #301844).
     */
    global boolean OnlyUpdateInstalled () {
	// changes onlyUpdateInstalled variable
	any default_ous_a = ProductFeatures::GetFeature ("software", "only_update_selected");

	boolean default_ous = nil;
	if (default_ous_a == nil || default_ous_a == "") {
	    y2error ("software/only_update_selected not defined");
	    return false;
	}
	if (is (default_ous_a, boolean)) default_ous = (boolean) default_ous_a;

	string installed_system = SuSERelease::ReleaseInformation (Installation::destdir);
	y2milestone ("Processing '%1' from '%2'", installed_system, Installation::destdir);

	if (installed_system == nil || installed_system == "") {
	    y2error ("Cannot find out installed system name");
	    return default_ous;
	}
	
	any reverse_ous_a = ProductFeatures::GetFeature ("software", "only_update_selected_reverse_list");
	// No reverse rules defined
	if (reverse_ous_a == "") {
	    return default_ous;
	}
	// not a list or empty list
	list <string> reverse_ous = (list <string>) reverse_ous_a;
	if (reverse_ous == nil || reverse_ous == []) return default_ous;

	if (ListOfRegexpsMatchesProduct (reverse_ous, installed_system)) {
	    return (! default_ous);
	}

	return default_ous;
    }

    /**
     * Returns whether upgrade process should silently downgrade packages if needed.
     * 'true' means that packages might be downgraded, 'nil' is returned when
     * the feature is not supported in the control file.
     */
    global boolean SilentlyDowngradePackages () {
	// returns empty string if not defined, buggy GetBooleanFeature
	any default_sdp_a = ProductFeatures::GetFeature ("software", "silently_downgrade_packages");

	boolean default_sdp = nil;
	if (default_sdp_a == nil || default_sdp_a == "") {
	    y2milestone ("software/silently_downgrade_packages not defined");
	    return nil;
	}
	if (is (default_sdp_a, boolean)) default_sdp = (boolean) default_sdp_a;

	string installed_system = SuSERelease::ReleaseInformation (Installation::destdir);
	y2milestone ("Processing '%1' from '%2'", installed_system, Installation::destdir);

	if (installed_system == nil || installed_system == "") {
	    y2error ("Cannot find out installed system name");
	    return default_sdp;
	}
	
	any reverse_sdp_a = ProductFeatures::GetFeature ("software", "silently_downgrade_packages_reverse_list");
	// No reverse rules defined
	if (reverse_sdp_a == "") {
	    return default_sdp;
	}
	// not a list or empty list
	list <string> reverse_sdp = (list <string>) reverse_sdp_a;
	if (reverse_sdp == nil || reverse_sdp == []) return default_sdp;

	if (ListOfRegexpsMatchesProduct (reverse_sdp, installed_system)) {
	    return (! default_sdp);
	}

	return default_sdp;
    }

    /**
     * Returns whether the installed product is supported for upgrade.
     * (Functionality for FATE #301844).
     */
    global boolean IsProductSupportedForUpgrade () {
	string installed_system = SuSERelease::ReleaseInformation (Installation::destdir);
	y2milestone ("Processing '%1' from '%2'", installed_system, Installation::destdir);
	
	if (installed_system == nil || installed_system == "") {
	    y2error ("Cannot find out installed system name");
	    return false;
	}

	any supported_products_a = ProductFeatures::GetFeature ("software", "products_supported_for_upgrade");
	// No products defined
	if (supported_products_a == "") {
	    y2warning ("No products_supported_for_upgrade defined");
	    return true;
	}
	// not a list or empty list
	list <string> supported_products = (list <string>) supported_products_a;
	if (supported_products == nil || supported_products == []) return true;

	if (ListOfRegexpsMatchesProduct (supported_products, installed_system)) {
	    return true;
	}

	return false;
    }


    /*-----------------------------------------------------------------------
     * GLOBAL FUNCTIONS
     *-----------------------------------------------------------------------*/


global list<string> SelectedProducts () {
    list<map<string,any> > selected
	= Pkg::ResolvableProperties ("", `product, "");
    selected = filter (map<string,any> p, selected, {
	return p["status"]:nil == `selected;
    });
    return maplist (map<string,any> p, selected, {
	// TRANSLATORS: "Update to: $product_name"
	return p["display_name"]:p["summary"]:p["name"]:p["version"]:_("Unknown Product");
    });
}

/**
 * Check if installed product and product to upgrade to are compatible
 * @return boolean true if update is possible
 */
global boolean ProductsCompatible () {
    if (_products_compatible == nil)
    {
	if (Stage::normal ())
	{
	    // check if name of one of the products on the installation
	    // media is same as one of the installed products
	    // assuming that multiple products on installation media
	    // are compatible and compatibility is transitive
	    list<map<string,any> > inst =
		Pkg::ResolvableProperties ("", `product, "");
	    inst = filter (map<string,any> p, inst, {
		return p["status"]:nil == `installed;
	    });
	    list<string> inst_names = maplist (map<string,any> p, inst, {
		return p["name"]:"";
	    });
	    list<string> to_install = maplist (integer src,
		Pkg::SourceGetCurrent (true),
	    {
		map<string,string> prod_info = Pkg::SourceProduct (src);
		return prod_info["name"]:"";
	    });
	    // filter out empty products
	    to_install = filter (string o_p, to_install, { return o_p != ""; });

	    y2milestone ("Installed products: %1", inst_names);
	    y2milestone ("Products on installation media: %1", to_install);

	    // at least one product name found
	    if (size (to_install) > 0) {
		string equal_product = find (string i, inst_names, {
		    string found = find (string u, to_install, {
			return u == i;
		    });
		    return found != nil;
		});
		_products_compatible = equal_product != nil;
	    // no product name found
	    // bugzilla #218720, valid without testing according to comment #10
	    } else {
		y2warning ("No products found, setting product-compatible to 'true'");
		_products_compatible = true;
	    }
	}
	else
	{
	    _products_compatible = true; // FIXME this is temporary
	}
	y2milestone ("Products found compatible: %1", _products_compatible);
    }

    return _products_compatible;
}

global void IgnoreProductCompatibility () {
    _products_compatible = true;

}

    /**
     * Set initial values for variables that user can't change.
     * They are defined in the control file.
     */
    global define void InitUpdate () {
	y2milestone ("Calling: InitUpdate()");

	silentlyDowngradePackages = SilentlyDowngradePackages();
	y2milestone ("silentlyDowngradePackages: %1", silentlyDowngradePackages);
    }

    /**
     * Drops packages defined in control file (string) software->dropped_packages
     *
     * @see bnc #300540
     */
    global void DropObsoletePackages () {
	string packages_to_drop = ProductFeatures::GetStringFeature ("software", "dropped_packages");

	if (packages_to_drop == nil || packages_to_drop == "") {
	    y2milestone ("No obsolete packages to drop");
	    return;
	}

	list <string> l_packages_to_drop = splitstring (packages_to_drop, ", \n");
	y2milestone ("Packages to drop: %1", l_packages_to_drop);

	foreach (string one_package, l_packages_to_drop, {
	    if (Pkg::PkgInstalled (one_package) || Pkg::IsSelected (one_package)) {
		y2milestone ("Package to delete: %1", one_package);
		Pkg::PkgDelete (one_package);
	    }
	});
    }

    /**
     *
     */
    global define void Reset ()
    {
	y2milestone ("Calling: UpdateReset()");

	Update::InitUpdate();

//	deleteOldPackages = DeleteOldPackages();
//	y2milestone ("deleteOldPackages %1", deleteOldPackages);

	onlyUpdateInstalled = OnlyUpdateInstalled();
	y2milestone ("onlyUpdateInstalled %1", onlyUpdateInstalled);

	disallow_upgrade = false;

	manual_interaction = false;
	products_incompatible = false;
	_products_compatible = nil;

	Installation::update_backup_modified = true;
	Installation::update_backup_sysconfig = true;
	Installation::update_remove_old_backups = false;
	Installation::update_backup_path = "/var/adm/backup";
    }


    /**
     *
     */
    global define void fill_version_map (map <string, any>& data)
    {
	if (data["name"]:"?" == "?" && data["version"]:"?" == "?") {
	    data["nameandversion"] = "?";
	} else {
	    data["nameandversion"] = data["name"]:"?" + " " + data["version"]:"?";
	}

	list <string> tmp0 = [];
	if (regexpmatch (data["version"]:"", " -")) {
	    splitstring (data["version"]:"", " -");
	}

	list <string> tmp1 = [];
	if (regexpmatch (tmp0[0]:"", "\.")) {
	    splitstring (tmp0[0]:"", ".");
	}

	integer tmp2 = tointeger (tmp1[0]:"-1");
	if (tmp2 >= 0)
	    data["major"] = tmp2;

	integer tmp3 = tointeger (tmp1[1]:"-1");
	if (tmp3 >= 0)
	    data["minor"] = tmp3;
    }


    /**
     * Read product name and version for the old and new release.
     * Fill Installation::installedVersion and Installation::updateVersion.
     * @return success
     */
    global define boolean GetProductName ()
    {
	Installation::installedVersion = $[];
	Installation::updateVersion = $[];

	// get old product name

	// cannot use product information from package manager
	// for pre-zypp products
	// #153576
	string old_name = SuSERelease::ReleaseInformation
	    (Installation::destdir);
	y2milestone("SuSERelease::ReleaseInformation: %1", old_name);

	// Remove 'Beta...' from product release
	if (regexpmatch (old_name, "Beta")) {
	    old_name = regexpsub (old_name, "^(.*)[ \t]+Beta.*$", "\\1");
	// Remove 'Alpha...' from product release
	} else if (regexpmatch (old_name, "Alpha")) {
	    old_name = regexpsub (old_name, "^(.*)[ \t]+Alpha.*$", "\\1");
	}

	integer p = findlastof (old_name, " ");
	if (p == nil)
	{
	    y2error ("release info <%1> is screwed", old_name);
	    Installation::installedVersion = $[];
	}
	else
	{
	    Installation::installedVersion["show"] = old_name;
	    Installation::installedVersion["name"] = substring (old_name, 0, p);
	    Installation::installedVersion["version"] = substring (old_name, p + 1);
	    fill_version_map (Installation::installedVersion);
	}

	// "minor" and "major" version keys
	// bug #153576, "version" == "9" or "10.1" or ...
	string inst_ver = Installation::installedVersion["version"]:"";
	if (inst_ver != "" && inst_ver != nil) {
	    // SLE, SLD, OES...
	    if (regexpmatch (inst_ver, "^[0123456789]+$")) {
		Installation::installedVersion["major"] = tointeger (inst_ver);
	    // openSUSE
	    } else if (regexpmatch (inst_ver, "^[0123456789]+\.[0123456789]+$")) {
		Installation::installedVersion["major"] = tointeger (regexpsub (inst_ver, "^([0123456789]+)\.[0123456789]+$", "\\1"));
		Installation::installedVersion["minor"] = tointeger (regexpsub (inst_ver, "^[0123456789]+\.([0123456789]+)$", "\\1"));
	    } else {
		y2error("Cannot find out major/minor from >%1<", inst_ver);
	    }
	} else {
	    y2error("Cannot find out version: %1", Installation::installedVersion);
	}
	
	if (Mode::test()) {
	    y2error ("Skipping detection of new system");
	    return true;
	}

	// get new product name

	integer num = size (Packages::theSources);

	if (num <= 0)
	{
	    y2error ("No source");
	    Installation::updateVersion["name"] = "?";
	    Installation::updateVersion["version"] = "?";
	    fill_version_map (Installation::updateVersion);
	    return false;
	}

	integer update_to_source = nil;
	y2milestone ("Known sources: %1", Packages::theSources);

	// So-called System Update
	if (Stage::normal()) {
	    foreach (integer source_id, Packages::theSources, {
		map source_map = Pkg::SourceProductData (source_id);

		// source need to be described
		if (source_map != $[]) {
		    if (source_map["productversion"]:"A" == Installation::installedVersion["version"]:"B") {
			y2milestone ("Found matching product: %1", source_map);
			update_to_source = source_id;
		    } else {
			y2error ("Found non-matching product: %1", source_map);
			// every invalid product is selected
			if (update_to_source == nil)
			    update_to_source = source_id;
		    }
		}
	    });
	}

	// fallback for Stage::normal()
	if (Stage::normal()) {
	    if (update_to_source == nil) update_to_source = Packages::theSources[num-1]:0;
	// default for !Stage::normal
	} else {
	    update_to_source = Packages::GetBaseSourceID();
	}
	
	map new_product = Pkg::SourceProductData (update_to_source);
	map new_source  = Pkg::SourceGeneralData (update_to_source);

	y2milestone ("Product to update to: %1 %2 %3", update_to_source, new_product, new_source);

	if (new_product == nil)
	{
	    Installation::updateVersion["name"] = "?";
	    Installation::updateVersion["version"] = "?";
	    y2error("Cannot find out source details: %1", Installation::updateVersion);
	    fill_version_map (Installation::updateVersion);
	    return false;
	}

	// bugzilla #225256, use "label" first, then a "productname"
	Installation::updateVersion["show"] = new_product["label"]:nil;
	if (Installation::updateVersion["show"]:nil == nil) {
	    y2warning ("No 'label' defined in product");

	    if (new_product["productname"]:"?" == "?" && new_product["productversion"]:"?" == "?") {
		Installation::updateVersion["show"] = "?";
	    } else {
		Installation::updateVersion["show"] = new_product["productname"]:"?" + " " + new_product["productversion"]:"?";
	    }
	}
	Installation::updateVersion["name"] = new_product["label"]:new_product["productname"]:"?";
	Installation::updateVersion["version"] = new_product["productversion"]:"?";
	fill_version_map (Installation::updateVersion);

	string new_ver = Installation::updateVersion["version"]:"";
	if (new_ver != "" && new_ver != nil) {
	    // SLE, SLD, OES...
	    if (regexpmatch (new_ver, "^[0123456789]+$")) {
		Installation::updateVersion["major"] = tointeger (new_ver);
	    // openSUSE
	    } else if (regexpmatch (new_ver, "^[0123456789]+\.[0123456789]$")) {
		Installation::updateVersion["major"] = tointeger (regexpsub (new_ver, "^([0123456789]+)\.[0123456789]$", "\\1"));
		Installation::updateVersion["minor"] = tointeger (regexpsub (new_ver, "^[0123456789]+\.([0123456789])$", "\\1"));
	    } else {
		y2error("Cannot find out major/minor from %1", new_ver);
	    }
	} else {
	    y2error("Cannot find out version: %1", Installation::updateVersion);
	}

	y2milestone ("update from %1 to %2", Installation::installedVersion, Installation::updateVersion);

	return true;
    }

    global list<string> GetBasePatterns ()
    {
        // get available base patterns
        list<map<string,any> > patterns = Pkg::ResolvableProperties ("", `pattern, "");
        patterns = filter (map<string,any> p, patterns, {
            if (p["status"]:nil != `selected && p["status"]:nil != `available)
                return false;
            // if type != base
            return true;
        });
	return maplist (map<string,any> p, patterns, {
	   return p["name"]:"";
	});
    }


    /**
     * Get all available base selections sorted in reverse order
     * (highest ordered bases selection comes first).
     */
    global define list<string> GetBaseSelections ()
    {
	list<string> available_base_selections = sort (string x, string y, Pkg::GetSelections (`available, "base"), {
	    map xmap = Pkg::SelectionData(x);
	    map ymap = Pkg::SelectionData(y);
	    return (xmap["order"]:"" > ymap["order"]:"");
	});
	y2milestone ("available_base_selections %1", available_base_selections);
	return available_base_selections;
    }

    string ReadInstalledDesktop() {
	SCR::Execute (.target.bash, "/bin/mv -f /etc/sysconfig/windowmanager /etc/sysconfig/windowmanager.old");
	SCR::Execute (.target.bash, "/bin/ln -s /mnt/etc/sysconfig/windowmanager /etc/sysconfig/windowmanager");
	string ret = (string)SCR::Read (.sysconfig.windowmanager.DEFAULT_WM);
	SCR::Execute (.target.bash, "/bin/rm -f /etc/sysconfig/windowmanager");
	SCR::Execute (.target.bash, "/bin/mv -f /etc/sysconfig/windowmanager.old /etc/sysconfig/windowmanager");
	return ret;
    }

    global void SetDesktopPattern() {
	string desktop = ReadInstalledDesktop();
	if (desktop == "kde" || desktop == "gnome")
	{
	    y2milestone ("Selecting pattern to install: %1", desktop);
	    Pkg::ResolvableInstall (desktop, `pattern);
	}
    }

    /**
     * Propose a selection for the update and save it's name in
     * Update::selected_selection.
     */
    global define void ProposeSelection ()
    {
	selected_selection = "";

	list available_selections = GetBaseSelections ();

	// nulth try: teh default desktop

	string desktop = ReadInstalledDesktop();
	map wm2sel = $[
	    "kde" : "default",
	    "gnome" : "default-Gnome",
	];
	selected_selection = wm2sel[desktop]:"";

	if (!contains (available_selections, selected_selection))
	    selected_selection = "";

	if (selected_selection != "")
	{
	    y2milestone ("using default desktop %1 to define selection: %2",
		desktop, selected_selection);
	    return;
	}

	// first try: installed one

	list tmp1 = Pkg::GetSelections (`installed, "base");
	if (tmp1 != nil && tmp1 != [])
	    selected_selection = tmp1[0]:"";

	if (!contains (available_selections, selected_selection))
	    selected_selection = "";

	if (selected_selection != "") {
	    y2milestone ("using installed selection: %1", selected_selection);
	    return;
	}

	// second try: available selection with highest order

	if (size (available_selections) > 0)
	    selected_selection = available_selections[0]:"";

	if (selected_selection != "") {
	    y2milestone ("using highest order selection: %1", selected_selection);
	    return;
	}

	// error: no selection available

	y2error ("no selection available");

    }


    /**
     *
     */
    global define void Detach ()
    {
	Pkg::TargetFinish ();
	did_init1 = false;
	did_init2 = false;
    }

    void TextsUsedInFuture () {
	// TRANSLATORS: check-box, it might happen that we need to downgrade some packages during update
	string aaa = _("Allow Package Downgrade");
    }

}

ACC SHELL 2018