ACC SHELL

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

/**
 * Module:
 *	Misc
 * File:
 *	Misc.ycp
 * Purpose:
 *	miscellaneous definitions for installation
 * Author:	Klaus Kaempf <kkaempf@suse.de>
 * $Id: Misc.ycp 56192 2009-03-17 19:32:08Z lslezak $
 */
{

    module "Misc";

    import "Mode";


    /*
     * Message after finishing installation and before the system
     * boots for the first time.
     *
     */
    global string boot_msg = "";

    /**
     * @param	first	string	name of first file to try
     * @param	second	string	name of second file to try
     * @return	any	content of file
     *
     * try to read first file, if it doesn't exist, read second
     * files must reside below /usr/lib/YaST2
     * files must have ycp syntax
     */

    global define any ReadAlternateFile ( string first, string second)
    ``{
	any result = SCR::Read (.target.yast2, [first, nil]);
	if (result == nil)
	    result = SCR::Read (.target.yast2, second);
	return result;
    }

    /**
     * @param	hardware_entry	map	map of .probe entry
     * @return	string	vendor and device name
     *
     * common function to extract 'name' of hardware
     */

    global define string hardware_name (map hardware_entry)
    ``{
	string sub_vendor = "";
	string sub_device = "";

	sub_vendor = hardware_entry["sub_vendor"]:"";
	sub_device = hardware_entry["sub_device"]:"";

	if ((sub_vendor != "") && (sub_device != ""))
	{
	    return (sub_vendor + "\n" + sub_device);
	}
	else
	{
	    string vendor = hardware_entry["vendor"]:"";
	    return (vendor
		    + ((vendor != "") ? "\n" : "")
		    + hardware_entry["device"]:"");
	}
    }


    /**
     * @param lmap	map	map of language codes and translations
     *				e.g. $[ "default" : "Defaultstring", "de" : "German....", ...]
     * @param lang	string	language as ISO code, either 2 chars (de)
     *				or 5 chars (de_DE)
     * @return	string		translation
     *
     * Define a macro that looks up a localized string in a language map
     * of the form $[ "default" : "Defaultstring", "de" : "German....", ...]
     */

    global define string translate(map lmap, string lang)
    ``{
	string t = lmap[lang]:"";
	if ((size (t) == 0)
	    && size(lang) > 2)
	{
	    t = lmap[substring(lang, 0, 2)]:"";
	}
	if (size (t) == 0)
	{
	    t = lmap["default"]:"";
	}

	return t;
    }

    /**
     * SysconfigWrite()
     * @param	path level	path behind .sysconfig for all values
     * @param	list values	list of [ .NAME, value] lists
     *
     * @returns boolean		false if SCR::Write reported error
     *
     * write list of sysyconfig entries via rcconfig agent
     */

    global define boolean SysconfigWrite (path level, list<list> values)
    ``{
	boolean result = true;
	if (level == .)
	    level = .sysconfig;
	else
	    level = .sysconfig + level;

	foreach (list entry, values,
	``{
	    if (size (entry) != 2)
		y2error ("bad entry in rc_write()");
	    else
	    {
		if (!SCR::Write (level + entry[0]:., entry[1]:""))
		    result = false;
	    }
	});
	return result;
    }



    /**
     * MergeOptions
     * Merges "opt1=val1 opt2=val2 ..." and $["opta":"vala", ..."]
     * to $["opt1":"val1", "opt2":"val2", "opta":"vala", ...]
     * as needed by modules.conf agent
     * @param options	string	module options, e.g. "opt1=val1 opt2=val2 ..."
     * @param optmap	map	possible old options $["opta":"vala", ...]
     * @returns map	$["opt1":"val1", "opt2":"val2", ...]
     */

    global define map SplitOptions (string options, map optmap)
    ``{
	// step 1: split "opt1=val1 opt2=val2 ..."
	// to ["opt1=val1", "opt2=val2", "..."]

	list<string> options_split = splitstring (options, " ");

	foreach (string options_element, options_split,
	``{
	    list options_values = splitstring (options_element, "=");

	    if ((size (options_values) == 1)
		&& (optmap[options_element]:"" == ""))
	    {
		// single argument
		optmap[options_element] = "";
	    }
	    else if (size (options_values) == 2)
	    {
		// argument with value
		optmap[options_values[0]:""] = options_values[1]:"";
	    }
	});
	return optmap;
    }


    /**
     * SysconfigRead()
     *
     * Try an SCR::Read(...) and return the result if successful.
     * On failure return the the second parameter (default value)
     *
     * @param	sysconfig_path   Sysconfig SCR path.
     * @param	defaultv         Default value
     *
     * @return  Success --> Result of SCR::Read<br>
     *		Failure --> Default value
     *
     */

    global define string SysconfigRead( path sysconfig_path, string defaultv )
    ``{
	string local_ret = (string)SCR::Read( sysconfig_path );

	if ( local_ret == nil )
	{
	    y2warning("Failed reading '%1', using default value", sysconfig_path );
	    return( defaultv );
	}
	else
	{
	    y2milestone("%1: '%2'", sysconfig_path, local_ret );
	    return( local_ret );
	}
    }	// SysconfigRead()

    /**
     * Try to read value from sysconfig file and return the result if successful.
     * Function reads from arbitrary sysconfig file, for which the agent
     * doesn't exist: e.g. from different partition like /mnt/etc/sysconfig/file.
     *
     * @param	key		Key of the value we want to read from sysconfig file.
     * @param	defaultv        Default value
     * @param	location	Full path to target sysconfig file.
     *
     * @return  Success --> Result of SCR::Read<br>
     *		Failure --> Default value
     *
     * @example Misc::CustomSysconfigRead ("INSTALLED_LANGUAGES", "", Installation::destdir + "/etc/sysconfig/language");
     *
     */
    global define string CustomSysconfigRead (string key, string defval,string location)
    {
	if (location == "")
	    return defval;

	path custom_path = topath (location);
        SCR::RegisterAgent (custom_path, `ag_ini(
	    `SysConfigFile (location)
	));
	string ret = SysconfigRead (add (custom_path, key), defval);
	SCR::UnregisterAgent (custom_path);
	return ret;
    }


    /**
     * 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);

	integer processID = (integer)SCR::Execute(.process.start_shell, run_command);

	if (processID == 0) {
	    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(.process.running, processID);
	    // 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  = splitstring((string)SCR::Read(.process.read, processID), "\n");
	    y2milestone ("getting errors");
	    script_err  = splitstring((string)SCR::Read(.process.read_stderr, processID), "\n");
	    y2milestone ("getting status");
	    return_code = (integer) SCR::Read(.process.status, processID);
	}
	y2milestone ("killing");
	SCR::Execute(.process.kill, processID);

	// release the process from the agent
	SCR::Execute(.process.release, processID);

	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' (FIXME still needed???)
     * @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;
    }

}

ACC SHELL 2018