ACC SHELL
/**
* File: modules/Sysconfig.ycp
* Package: Configuration of sysconfig
* Summary: Data for configuration of sysconfig, input and output functions.
* Authors: Ladislav Slezak <lslezak@suse.cz>
*
* $Id: Sysconfig.ycp 37399 2007-04-11 13:54:49Z lslezak $
*
* Representation of the configuration of sysconfig.
* Input and output routines.
*/
{
module "Sysconfig";
textdomain "sysconfig";
import "Progress";
import "Report";
import "Summary";
import "Directory";
import "Label";
import "IP";
import "String";
import "Service";
import "Mode";
global list<string> configfiles = ["/etc/sysconfig/*", "/etc/sysconfig/network/ifcfg-*",
"/etc/sysconfig/network/dhcp",
"/etc/sysconfig/network/config", Directory::ydatadir + "/descriptions",
"/etc/sysconfig/powersave/*", "/etc/sysconfig/uml/*"
];
// Additional files from Import
list custom_files = [];
// all read variables
map variables = $[];
// modified variables
map<string, string> modified_variables = $[];
// comment for non-variable nodes
map node_comments = $[];
// location for each variable
map<string,string> variable_locations = $[];
global map parse_param = $[
"separator" : ",",
"unique" : true,
"remove_whitespace" : true
];
global boolean write_only = false;
global list<list> tree_content = [];
// map of actions to start when variable is modified
map<string, any> actions = $[];
global boolean ConfirmActions = false;
boolean config_modified = false;
/**
* Data was modified?
* @return true if modified
*/
global define boolean Modified() ``{
return (size(modified_variables) > 0) || config_modified;
};
global define void SetModified() {
config_modified = true;
}
/**
* Get variable name from variable identification or empty string if input is invalid
* @param id Variable identification
* @return string Variable name
* @example get_name_from_id("var$file") -> "var"
*/
global define string get_name_from_id(string id) ``{
if (id == nil)
{
return "";
}
integer pos = findfirstof(id, "$");
if (pos != nil && pos >= 0)
{
return substring(id, 0, findfirstof(id, "$"));
}
else
{
return "";
}
}
/**
* Get file name where is variable located from variable identification
* @param id Variable identification
* @return string File name
*/
global define string get_file_from_id(string id) ``{
if (id == nil)
{
return "";
}
integer pos = findfirstof(id, "$");
if (pos != nil && pos >= 0)
{
return substring(id, pos + 1);
}
else
{
return "";
}
}
/**
* Get comment without metadata
* @param input Input string
* @return string Comment used as variable description
*/
global define string get_only_comment(string input) ``{
if (input == nil || input == "")
{
return "";
}
list<string> lines = splitstring(input, "\n");
string ret = "";
foreach(string line, lines, ``{
string com_line = regexpsub(line, "^#([^#].*)", "\\1");
if (com_line == nil)
{
// add empty lines
if (regexpmatch(line, "^#[ \t]*$") == true)
{
ret = ret + "\n";
}
}
else
{
ret = ret + com_line + "\n";
}
}
);
return ret;
}
/**
* Search in syscnfig files for value
* @param params search parameters
* @param show_progress if true progress bar will be displayed
* @return list<string> List of found variables (IDs)
*/
global define list<string> Search(map params, boolean show_progress) ``{
list<string> found = [];
// get all configuration files
list<string> files = (list<string>) SCR::Dir(.syseditor.section);
if (show_progress == true)
{
// Translation: Progress bar label
UI::OpenDialog(`ProgressBar(`id(`progress), _("Searching..."), size(files), 0));
}
boolean search_varname = params["varname"]:true;
boolean search_description = params["description"]:false;
boolean search_value = params["value"]:false;
boolean case_insensitive = params["insensitive"]:false;
string search_string = params["search"]:"";
if (search_string == "")
{
UI::CloseDialog();
return found;
}
if (case_insensitive == true)
{
search_string = tolower(search_string);
}
integer index = 0;
foreach(string file, files, ``{
// skip backup files
if (regexpmatch(file, "\\.bak$") || regexpmatch(file, "~$"))
{
y2milestone("Ignoring backup file %1", file);
continue;
}
// get all variables in file
path var_path = add(.syseditor.value, file);
list<string> variables = (list<string>)SCR::Dir(var_path);
y2debug("Searching in file %1", file);
foreach(string var, variables,
``{
boolean already_found = false;
y2debug("Searching in variable %1", var);
if (search_varname == true)
{
string var2 = var;
if (case_insensitive)
{
var2 = tolower(var);
}
if (issubstring(var2, search_string))
{
found = add(found, var + "$" + file);
already_found = true;
}
}
// search in variable value if it is requested and previous check was unsuccessful
if (search_value == true && already_found == false)
{
string read_value = (string) SCR::Read(add(add(.syseditor.value, file), var));
if (case_insensitive)
{
read_value = tolower(read_value);
}
if (issubstring(read_value, search_string))
{
found = add(found, var + "$" + file);
already_found = true;
}
}
if (search_description == true && already_found == false)
{
// read comment without metadata
string read_comment = get_only_comment((string) SCR::Read(add(add(.syseditor.value_comment, file), var)));
if (case_insensitive)
{
read_comment = tolower(read_comment);
}
if (issubstring(read_comment, search_string))
{
found = add(found, var + "$" + file);
}
}
}
);
if (show_progress == true)
{
index = index + 1;
UI::ChangeWidget(`id(`progress), `Value, index);
}
}
);
if (show_progress == true)
{
UI::CloseDialog();
}
y2debug("Found: %1", found);
return found;
}
/**
* Remove white spaces at beginning or at the end of string
* @param input Input string
* @return string String without white spaces
*/
global define string remove_whitespaces(string input) ``{
if (input == nil)
{
return nil;
}
string removed_whitespaces = regexpsub(input, "^[ \t]*(([^ \t]*[ \t]*[^ \t]+)*)[ \t]*$", "\\1");
return (removed_whitespaces != nil) ? removed_whitespaces : input;
}
/**
* Get metadata lines from input string
* @param input Input string
* @return list<string> Metadata lines in list
*/
global define list<string> get_metadata(string input) ``{
if (input == nil || input == "")
{
return [];
}
list<string> lines = splitstring(input, "\n");
return (filter(string line, lines, ``(regexpmatch(line, "^##.*"))));
}
/**
* Parse metadata from comment
* @param comment Input comment
* @return map parsed metadata
*/
global define map<string, string> parse_metadata(string comment) ``{
map<string, string> ret = $[];
// get metadata part of comment
list<string> metalines = get_metadata(comment);
list<string> joined_multilines = [];
string multiline = "";
y2debug("metadata: %1", metalines);
// join multi line metadata lines
foreach(string metaline, metalines, ``{
if (substring(metaline, size(metaline) - 1, 1) != "\\")
{
if (multiline != "")
{
// this not first multiline so remove comment mark
string without_comment = regexpsub(metaline, "^##(.*)", "\\1");
if (without_comment != nil)
{
metaline = without_comment;
}
}
joined_multilines = add(joined_multilines, multiline + metaline);
multiline = "";
}
else
{
string part = substring(metaline, 0, size(metaline) - 1);
if (multiline != "")
{
// this not first multiline so remove comment mark
string without_comment = regexpsub(part, "^##(.*)", "\\1");
if (without_comment != nil)
{
part = without_comment;
}
}
// add line to the previous lines
multiline = multiline + part;
}
}
);
y2debug("metadata after multiline joining: %1", joined_multilines);
// parse each metadata line
foreach(string metaline, joined_multilines, ``{
/* Ignore lines with ### -- general comments */
if (regexpmatch(metaline, "^###"))
{
return;
}
string meta = regexpsub(metaline, "^##[ \t]*(.*)", "\\1");
// split sting to the tag and value part
integer colon_pos = findfirstof(meta, ":");
string tag = "";
string val = "";
if (colon_pos == nil)
{
// colon is missing
tag = meta;
}
else
{
tag = substring(meta, 0, colon_pos);
if (size(meta) > colon_pos + 1)
{
val = substring(meta, colon_pos + 1);
}
}
// remove whitespaces from parts
tag = remove_whitespaces(tag);
val = remove_whitespaces(val);
y2milestone("tag: %1 val: '%2'", tag, val);
// add tag and value to map if they are present in comment
if (tag != "")
{
ret = (map<string, string>) add(ret, tag, val);
}
else
{
// ignore separator lines
if (!regexpmatch(metaline, "^#*$"))
{
y2warning("Unknown metadata line: %1", metaline);
}
}
}
);
return ret;
}
/**
* Get variable location in tree widget from variable identification
* @param id Variable identification
* @return string Variable location
*/
global define string get_location_from_id(string id) ``{
return variable_locations[id]:"";
}
/**
* Get description of selected variable
* @param varid Variable identification
* @return map Description map
*/
global define map<string, any> get_description(string varid) ``{
string varname = get_name_from_id(varid);
string fname = get_file_from_id(varid);
path comment_path = add(add(.syseditor.value_comment, fname), varname);
path value_path = add(add(.syseditor.value, fname), varname);
string comment = (string)SCR::Read(comment_path);
list<string> all_variables = (list<string>)SCR::Dir(add(.syseditor.value, fname));
string used_comment = varname;
// no comment present
if (comment != nil && size(comment) == 0 && !regexpmatch(fname, "^/etc/sysconfig/network/ifcfg-.*"))
{
y2warning("Comment for variable %1 is missing", varid);
list<string> reversed = [];
integer i = 0;
boolean found = false;
while (i < size(all_variables) && found == false)
{
string v = all_variables[i]:"";
if (v == varname)
{
found = true;
}
else
{
reversed = prepend(reversed, v);
}
i = i + 1;
}
if (found == true)
{
i = 0;
comment = "";
string v = "";
y2debug("reversed: %1", reversed);
while (i < size(reversed) && comment == "")
{
v = reversed[i]:"";
used_comment = v;
comment = (string) SCR::Read(add(add(.syseditor.value_comment, fname), v));
i = i + 1;
}
y2warning("Variable: %1 Using comment from variable: %2", varname, v);
}
}
// remove config file header at the beginning of the file
// header is comment from beginning of the file to the empty line
if (used_comment == all_variables[0]:"" && comment != nil)
{
y2debug("Reading first variable from the file");
// comment is read from the first variable
// remove header if it's present
y2debug("Whole comment: %1", comment);
list<string> lines = splitstring(comment, "\n");
list<string> filtered = [];
// remove last empty string from list (caused by last new line char)
if (lines[size(lines) - 1]:nil == "")
{
lines = remove(lines, size(lines) - 1);
}
if (contains(lines, "") == true)
{
y2milestone("Header comment detected");
boolean adding = false;
// filter out variables before empty line
filtered = filter(string line, lines, ``{
if (line == "")
{
adding = true;
}
else if (adding == true)
{
return true;
}
return false;
}
);
// merge strings
comment = mergestring(filtered, "\n");
}
}
map<string, any> meta = parse_metadata(comment);
string template_only_comment = "";
// for network configuration file read comments from configuration template
if (regexpmatch(fname, "^/etc/sysconfig/network/ifcfg-.*"))
{
string template_comment = (string) SCR::Read(add(add(.sysconfig.network.template, "value_comment"), varname));
map<string,string> template_meta = parse_metadata(template_comment);
if (size(template_meta) > 0)
{
// add missing metadata values from template
foreach(string key, string value, template_meta, ``{
if (!haskey(meta, key))
{
meta[key] = value;
}
}
);
}
template_only_comment = get_only_comment(template_comment);
if (size(template_only_comment) > 0)
{
template_only_comment = template_only_comment + "\n";
}
y2milestone("Comment read from template: %1", template_only_comment);
y2milestone("Meta read from template: %1", template_meta);
}
string deflt = (string) (meta["Default"]:nil);
if (deflt != nil)
{
list parsed = String::ParseOptions(deflt, parse_param);
meta["Default"] = parsed[0]:"";
y2debug("Read default value: %1", parsed[0]:"");
}
string new_value = modified_variables[varid]:nil;
// check if value was changed
if (new_value != nil)
{
meta["new_value"] = new_value;
}
meta["name"] = varname;
meta["file"] = get_file_from_id(varid);
meta["location"] = (varname != "") ? get_location_from_id(varid) : varid;
meta["comment"] = (varname != "") ? template_only_comment + get_only_comment(comment) : (node_comments[varid]:"");
meta["value"] = SCR::Read(value_path);
// add action commands
if (size(actions[varid]:$[]) > 0)
{
meta["actions"] = actions[varid]:$[];
}
return meta;
}
/**
* Set new variable value
* @param variable Variable identification
* @param new_value New value
* @param force If true - do not check if new value is valid
* @param force_change Force value as changed even if it is equal to old value
* @return symbol Result: `not_found (specified variable was not found in config file),
* `not_valid (new value is not valid - doesn't match variable type definition),
* `ok (success)
*/
global define symbol set_value(string variable, string new_value, boolean force, boolean force_change) ``{
map desc = get_description(variable);
string name = get_name_from_id(variable);
if (name == "")
{
return `not_found;
}
string modif = modified_variables[variable]:nil;
string old = desc["value"]:"";
// use default value (or emty string) instead of the curent value in autoyast
if (Mode::config())
{
old = (haskey(desc, "Default")) ? desc["Default"]:"" : "";
}
string curr_val = (modif != nil) ? modif : old;
if (force_change || new_value != curr_val)
{
y2milestone("variable: %1 changed from: %2 to: %3", variable, curr_val, new_value);
if (new_value == old && !force_change)
{
// variable was reset to the original value, remove it from map of modified
y2debug("Variable %1 was reset to the original value", variable);
modified_variables = (map<string, string>) remove(modified_variables, variable);
}
else
{
boolean valid = false;
if (force == false)
{
// check data type
string type = desc["Type"]:"string";
if (type == "string" || regexpmatch(type, "^string\\(.*\\)$") == true)
{
// string type is valid always
valid = true;
}
else if (type == "yesno")
{
valid = (new_value == "yes" || new_value == "no");
}
else if (type == "boolean")
{
valid = (new_value == "true" || new_value == "false");
}
else if (type == "integer")
{
valid = regexpmatch(new_value, "^-{0,1}[0-9]*$");
}
else if (regexpmatch(type, "^list\\(.*\\)$"))
{
string listopt = regexpsub(type, "^list\\((.*)\\)$", "\\1");
list parsed_opts = String::ParseOptions(listopt, parse_param);
valid = contains(parsed_opts, new_value);
}
else if (regexpmatch(type, "^integer\\(-{0,1}[0-9]*:-{0,1}[0-9]*\\)$"))
{
// check if input is integer
valid = regexpmatch(new_value, "^-{0,1}[0-9]*$");
if (valid == true)
{
// it is integer, check range
string min = regexpsub(type, "^integer\\((-{0,1}[0-9]*):-{0,1}[0-9]*\\)$", "\\1");
string max = regexpsub(type, "^integer\\(-{0,1}[0-9]*:(-{0,1}[0-9]*)\\)$", "\\1");
y2milestone("min: %1 max: %2", min, max);
integer min_int = tointeger(min);
integer max_int = tointeger(max);
integer new_int = tointeger(new_value);
y2milestone("min_int: %1 max_int: %2", min_int, max_int);
if (max != "" && min != "")
{
valid = (new_int >= min_int && new_int <= max_int);
}
else if (max == "")
{
valid = (new_int >= min_int);
}
else if (min == "")
{
valid = (new_int <= max_int);
}
else
{
// empty range, valid is set to true
y2warning("empty integer range, assuming any integer");
}
}
}
else if (regexpmatch(type, "^regexp\\(.*\\)$"))
{
string regex = regexpsub(type, "^regexp\\((.*)\\)$", "\\1");
valid = regexpmatch(new_value, regex);
}
else if (type == "ip")
{
// check IP adress using function from network/ip.ycp include
valid = IP::Check(new_value);
}
else if (type == "ip4")
{
// check IP adress using function from network/ip.ycp include
valid = IP::Check4(new_value);
}
else if (type == "ip6")
{
// check IP adress using function from network/ip.ycp include
valid = IP::Check6(new_value);
}
else
{
y2warning("Unknown data type %1 for variable %2", type, name);
}
}
if (valid == false && force == false)
{
return `not_valid;
}
else
{
modified_variables[variable] = new_value;
return `ok;
}
}
}
// value was not changed => OK
return `ok;
}
/**
* Return modification status of variable
* @param varid Variable identification
* @return boolean True if variable was modified
*/
global define boolean modified(string varid) ``{
return haskey(modified_variables, varid);
}
/**
* Get list of modified variables
* @return list List of modified variables
*/
global define list<string> get_modified()
``{
list<string> ret = [];
foreach(string varid, string new_value, modified_variables,
``{
ret = add(ret, varid);
}
);
return ret;
}
/**
* Get list of all variables
* @return list List of variable identifications
*/
global define list<string> get_all()
``{
list<string> ret = [];
foreach(string varid, string new_value, variable_locations,
``{
ret = add(ret, varid);
}
);
return ret;
}
/**
* Get map of all variables
* @return map Map of variable names, key is variable name, value is a list of variable identifications
*/
global define map<string, list<string> > get_all_names()
``{
map<string, list<string> > ret = $[];
foreach(string varid, string new_value, variable_locations,
``{
string name = get_name_from_id(varid);
if (haskey(ret, name) == true)
{
ret = (map<string, list<string> >) add(ret, name, add(ret[name]:[], varid));
}
else
{
ret = (map<string, list<string> >) add(ret, name, [varid]);
}
}
);
return ret;
}
/**
* Register .syseditor path (use INI agent in multiple file mode)
*/
global define void RegisterAgents() {
list<string> files = configfiles;
string tmpdir = (string) SCR::Read(.target.tmpdir);
if (tmpdir == nil || tmpdir == "")
{
y2security("Using /tmp directory !");
tmpdir = "/tmp";
}
// register configuration files in SCR using INI-agent
string agentdef = sformat(".syseditor\n\n`ag_ini(`IniAgent( %1,\n", files) + (string)SCR::Read(.target.string, Directory::ydatadir + "/sysedit.agent");
string tmp = tmpdir + "/sysconfig-agent.scr";
SCR::Write(.target.string, tmp, agentdef);
SCR::RegisterAgent(.syseditor, tmp);
}
/**
* Read all sysconfig variables
* @return true on success
*/
global define boolean Read() ``{
// TODO: solve custom_files parameter problem (used in Import)
// read only powerteak config or all sysconfig files
list<string> files = configfiles;
string tmpdir = (string) SCR::Read(.target.tmpdir);
if (tmpdir == nil || tmpdir == "")
{
y2security("Using /tmp directory !");
tmpdir = "/tmp";
}
// register .syseditor path
RegisterAgents();
// register agent for reading network template
string agentdef = sformat(".sysconfig.network.template,\n\n`ag_ini(`IniAgent(\"/etc/sysconfig/network/ifcfg.template\"\n,") + (string) SCR::Read(.target.string, Directory::ydatadir + "/sysedit.agent");
string tmp = tmpdir + "/sysconfig-template-agent.scr";
SCR::Write(.target.string, tmp, agentdef);
SCR::RegisterAgent(.sysconfig.network.template, tmp);
// list of all config files
y2milestone("Registered config files: %1", SCR::Dir(.syseditor.section));
// create script options
string param = "";
foreach(string par, files, ``{param = param + "'" + par + "' ";});
// create tree definition list and description map using external Perl script
SCR::Execute(.target.bash, Directory::bindir + "/parse_configs.pl " + param + "> " + tmpdir + "/treedef.ycp");
// read list
list parsed_output = (list) SCR::Read(.target.ycp, tmpdir + "/treedef.ycp");
tree_content = parsed_output[0]:[];
node_comments = parsed_output[1]:$[];
variable_locations = parsed_output[2]:$[];
// redefined variables (variables which are defined in more files)
map redefined_vars = parsed_output[3]:$[];
if (size(redefined_vars) > 0)
{
y2warning("Redefined variables: %1", redefined_vars);
}
// read map with activation commands
actions = parsed_output[4]:$[];
return true;
}
/**
* Display confirmation dialog
* @param message Confirmation message
* @param command Command to confirm
* @return symbol `cont - start command, `skip - skip this command, `abort - skip all remaining commands
*/
define symbol ConfirmationDialog(string message, string command) ``{
UI::OpenDialog(
`opt(`decorated),
`VBox(
`Label(message),
(size(command) > 0) ? `Label(_("Command: ") + command) : `Empty(),
`VSpacing(0.5),
`HBox(
`PushButton(`id(`cont), Label::ContinueButton()),
// button label
`PushButton(`id(`skip), _("S&kip")),
`PushButton(`id(`abort), Label::AbortButton())
)
)
);
symbol ret = nil;
while (ret != `cont && ret != `skip && ret != `abort)
{
ret = (symbol) UI::UserInput();
if (ret == `close)
{
ret = `abort;
}
}
UI::CloseDialog();
return ret;
}
/**
* Start activation command, ask user to confirm it when it is required.
* Display specified error message when the command fails.
* @param start_command Command to start
* @param label Progress bar label
* @param error Error message displayed when command failes
* @param confirm Confirmation messge
* @param confirmaction Display confirmation dialog
* @return symbol `success - command was started, `failed - command failed (non-zero exit value),
* `skip - command was skipped, `abort - command starting was aborted
*/
define symbol StartCommand(string start_command, string label, string error, string confirm, boolean confirmaction) ``{
if (size(start_command) == 0)
{
return `success;
}
// set progress bar label
Progress::Title(label);
if (confirmaction == true)
{
// show confirmation dialog
symbol input = ConfirmationDialog(confirm, start_command);
if (input != `cont)
{
return input;
}
}
y2milestone("Starting: %1", start_command);
integer exit = (integer) SCR::Execute(.target.bash, start_command + " > /dev/null 2> /dev/null");
y2milestone("Result: %1", exit);
if (exit != 0)
{
Report::Error(error);
return `failed;
}
return `success;
}
/**
* Write all sysconfig settings
* @return boolean true on success
*/
global define boolean Write() ``{
// remember all actions - start each action only once
map<string,boolean> Configmodules = $[];
map<string,boolean> Restarted = $[];
map<string,boolean> Reloaded = $[];
map<string,boolean> Commands = $[];
// will be complete SuSEconfig started?
boolean CompleteSuSEconfig = false;
// aborted?
boolean abort = false;
// SuSEconfig script name
string SuSEconfigName = "SuSEconfig";
// start presave commands
foreach (string vid, string new_val, modified_variables, ``{
if (abort)
{
return;
}
// get activation map for variable
string presave = (string) (actions[vid, "Pre"]:nil);
if (presave != nil && size(presave) > 0)
{
string confirm = _("A command will be executed");
string label = sformat(_("Starting command: %1..."), presave);
string error = sformat(_("Command %1 failed"), presave);
symbol precommandresult = StartCommand(presave, label, error, confirm, ConfirmActions);
if (precommandresult == `abort)
{
abort = true;
}
else if (precommandresult == `failed)
{
// PreSaveCommand returned non zero value
// remove activation data for failed variable
// (insert empty Command: to not start complete SuSEconfig)
actions[vid] = $["Cmd" : ""];
}
else if (precommandresult != `success && precommandresult != `skip)
{
y2error("Unknown return value from StartCommand(): %1", precommandresult);
}
}
}
);
if (abort)
{
return false;
}
foreach (string vid, string new_val, modified_variables, ``{
// get activation map for variable
map<string, any> activate = actions[vid]:$[];
string restart_service = (string) (activate["Rest"]:nil);
string reload_service = (string) (activate["Reld"]:nil);
string config_module = (string) (activate["Cfg"]:nil);
string bash_command = (string) (activate["Cmd"]:nil);
if (config_module == nil && reload_service == nil && restart_service == nil && bash_command == nil && CompleteSuSEconfig == false && !write_only)
{
// start complete SuSEconfig (backward compatibility)
CompleteSuSEconfig = true;
}
else
{
if (restart_service != nil && size(restart_service) > 0)
{
list<string> parsed = String::ParseOptions(restart_service, parse_param);
foreach(string s, parsed,
``{
Restarted[s] = true;
}
);
}
if (reload_service != nil && size(reload_service) > 0)
{
list<string> parsed = String::ParseOptions(reload_service, parse_param);
foreach(string s, parsed,
``{
Reloaded[s] = true;
}
);
}
if (config_module != nil && size(config_module) > 0)
{
list<string> parsed = String::ParseOptions(config_module, parse_param);
foreach(string s, parsed,
``{
Configmodules[s] = true;
}
);
}
if (bash_command != nil && size(bash_command) > 0)
{
Commands[bash_command] = true;
}
}
});
// write dialog caption
string caption = _("Saving sysconfig Configuration");
// set the right number of stages
integer steps = size(modified_variables) + size(Restarted) + size(Reloaded) + size(Commands) + ((CompleteSuSEconfig) ? 1 : size(Configmodules)) + 1 /* flush*/ + 3 /* 3 stages */;
// We do not set help text here, because it was set outside
Progress::New(caption, " ", steps, [
// progress bar item
_("Write the new settings"),
_("Activate the changes")
],
nil,
""
);
Progress::NextStage();
boolean ret = true;
// save each changed variable
foreach (string vid, string new_val, modified_variables,
``{
string file = get_file_from_id(vid);
string name = get_name_from_id(vid);
path value_path = add(add(.syseditor.value, file), name);
boolean written = SCR::Write(value_path, new_val);
if (written == false)
{
// error popup: %1 - variable name (e.g. DISPLAYMANAGER), %2 - file name (/etc/sysconfig/displaymanager)
Report::Error(sformat(_("Saving variable %1 to the file %2 failed."), name, file));
ret = false;
}
// progress bar label, %1 is variable name (e.g. DISPLAYMANAGER)
Progress::Title(sformat(_("Saving variable %1..."), name));
Progress::NextStep();
}
);
Progress::Title(_("Saving changes to the files..."));
// flush changes
SCR::Write(.syseditor, nil);
Progress::NextStep();
// now start required activation commands
Progress::NextStage();
// start SuSEconfig
if (CompleteSuSEconfig == true)
{
// action command is missing, start complete SuSEconfig (backward compatibility)
string start_command = "/sbin/SuSEconfig";
// message
string confirm = _("All configuration scripts will be started.");
// progeress bar label
string label = _("Starting configuration scripts...");
// Error message
string error = _("Configuration script failed.");
Progress::NextStep();
if (StartCommand(start_command, label, error, confirm, ConfirmActions) == `abort)
{
return false;
}
}
else if (size(Configmodules) > 0)
{
// start only required SuSEconfig modules
foreach(string modulename, boolean dummy, Configmodules,
``{
if (abort) return;
// action command is missing, start complete SuSEconfig (backward compatibility)
string start_command = sformat("/sbin/SuSEconfig --module %1", modulename);
string confirm = sformat(_("Configuration module %1 will be started."), modulename);
// progress bar label - %1 is module name
string label = sformat(_("Starting configuration module %1..."), modulename);
// error message (config module failed) - %1 is module name
string error = sformat(_("Configuration module %1 failed."), modulename);
Progress::NextStep();
if (StartCommand(start_command, label, error, confirm, ConfirmActions) == `abort)
{
abort = true;
}
}
);
}
if (abort) return false;
if (size(Reloaded) > 0)
{
// restart required services
foreach(string servicename, boolean dummy, Reloaded,
``{
if (abort) return;
// check whether service is running
string check_command = sformat("/etc/init.d/%1 status", servicename);
integer result = (integer)SCR::Execute(.target.bash, check_command);
y2milestone("%1 service status: %2", servicename, result);
if (result == 0)
{
// service is running, reload it
string start_command = sformat("/etc/init.d/%1 reload", servicename);
string confirm = sformat(_("Service %1 will be reloaded"), servicename);
string label = sformat(_("Reloading service %1..."), servicename);
string error = sformat(_("Reload of the service %1 failed"), servicename);
Progress::NextStep();
if (StartCommand(start_command, label, error, confirm, ConfirmActions) == `abort)
{
abort = true;
}
}
}
);
}
if (abort) return false;
if (size(Restarted) > 0)
{
// restart required services
foreach(string servicename, boolean dummy, Restarted,
``{
// check whether service is running
string check_command = sformat("/etc/init.d/%1 status", servicename);
integer result = (integer)SCR::Execute(.target.bash, check_command);
y2milestone("%1 service status: %2", servicename, result);
Progress::NextStep();
if (result == 0)
{
// service is running, restart it
string start_command = sformat("/etc/init.d/%1 restart", servicename);
string confirm = sformat(_("Service %1 will be restarted"), servicename);
string label = sformat(_("Restarting service %1..."), servicename);
string error = sformat(_("Restart of the service %1 failed"), servicename);
if (StartCommand(start_command, label, error, confirm, ConfirmActions) == `abort)
{
abort = true;
}
}
}
);
}
if (size(Commands) > 0)
{
// start generic commands
foreach(string cmd, boolean dummy, Commands,
``{
y2milestone("Command: %1", cmd);
Progress::NextStep();
if (size(cmd) > 0)
{
string confirm = _("A command will be executed");
string label = sformat(_("Starting command: %1..."), cmd);
string error = sformat(_("Command %1 failed"), cmd);
if (StartCommand(cmd, label, error, confirm, ConfirmActions) == `abort)
{
abort = true;
}
}
}
);
}
if (abort) return false;
// set 100% in progress bar
Progress::NextStep();
Progress::Title(_("Finished"));
// set "finished" mark for the last stage
Progress::NextStage();
return ret;
}
/**
* Set all sysconfig settings from the list
* (For use by autoinstallation.)
* @param settings The YCP structure to be set.
*/
global define void Set(list<map> settings) ``{
if (settings != nil)
{
modified_variables = $[];
custom_files = configfiles;
// convert from 8.1 export format
foreach(map setting, settings,
``{
string n = setting["sysconfig_key"]:"";
string f = setting["sysconfig_path"]:"";
string v = setting["sysconfig_value"]:"";
// compatibility mode for older release with relative path
if (findfirstof(f, "/") != 0)
{
f = sformat("/etc/sysconfig/%1", f);
}
string key = sformat("%1$%2", n, f);
modified_variables = (map<string, string>) add(modified_variables, key, v);
// add configuration file if it isn't already specified
if (!contains(custom_files, f))
{
custom_files = add(custom_files, f);
}
}
);
}
}
/**
* Set all sysconfig settings from the list and read information from files
* (For use by autoinstallation.)
* @param settings The YCP structure to be imported.
* @return boolean True on success
*/
global define boolean Import (list settings) ``{
list<map> settings_maps = (list<map>) settings;
// set values in the list
Set(settings_maps);
// register agent for user defined files, read values
return true;
}
/**
* Dump the sysconfig settings to a single map
* (For use by autoinstallation.)
* @return list Dumped settings (later acceptable by Import ())
*/
global define list Export () ``{
// return structured map (for 8.1 compatibility)
list ret = [];
if (size(modified_variables) > 0)
{
foreach(string varid, string val, modified_variables,
``{
string n = get_name_from_id(varid);
string f = get_file_from_id(varid);
map m = $[
"sysconfig_key" : n,
"sysconfig_path" : f,
"sysconfig_value" : val
];
ret = add(ret, m);
}
);
}
return ret;
}
/**
* Create a textual summary
* @return summary of the current configuration
*/
global define string Summary() ``{
// configuration summary headline
string summary = Summary::AddHeader("", _("Configuration Summary"));
y2milestone("Summary: %1", modified_variables);
if (size(modified_variables) > 0)
{
foreach(string varid, string newval, modified_variables,
``{
string varnam = get_name_from_id(varid);
string filename = get_file_from_id(varid);
summary = Summary::AddLine(summary, sformat("%1=\"%2\" (%3)", varnam, newval, filename));
}
);
}
else
{
summary = Summary::AddLine(summary, Summary::NotConfigured());
}
return summary;
}
/* EOF */
}
ACC SHELL 2018