ACC SHELL
/**
* File: include/inetd/routines.ycp
* Package: Configuration of inetd
* Summary: Miscelanous functions for configuration of inetd.
* Authors: Petr Hadraba <phadraba@suse.cz>
* Martin Lazar <mlazar@suse.cz>
*
* $Id: routines.ycp 50401 2008-08-27 10:52:41Z locilka $
*/
{
textdomain "inetd";
import "Inetd";
import "Progress";
import "Service";
import "Popup";
import "Package";
import "UsersCache";
import "String";
define term ServiceToTableItem (map service, integer ni_index);
define boolean ServicesMatch (map<string, any> a, map<string, any> b);
define boolean IsInstalled (string rpm);
/**
* Check for pending Abort press
* @return true if pending abort
*/
define boolean PollAbort() ``{
return UI::PollInput() == `abort;
}
/**
* If modified, ask for confirmation
* @return true if abort is confirmed
*/
define boolean ReallyAbort() ``{
return !Inetd::Modified() || Popup::ReallyAbort(true);
}
/**
* Progress::NextStage and Progress::Title combined into one function
* @param title progressbar title
*/
define void ProgressNextStage(string title) ``{
Progress::NextStage();
Progress::Title(title);
}
/**
* Used for cpmparisons whether the servers match:
* If server is /usr/sbin/tcpd, consider server_args instead.
* Then take the firse word (strips arguments or the parenthesized pkg name).
* Then take the last slash-delimited component.
* For sparse matching: nil is returned if server is nil
* (or if server args is nil AND is needed)
* @param server "server" field of a service
* @param server_args "server_args" field of a service
* @return basename of the real server
*/
define string GetServerBasename (string server, string server_args) ``{
string result = server;
// discard tcpd
if (result == "/usr/sbin/tcpd")
{
result = server_args;
}
// check nil
if (result != nil)
{
// program only
result = String::FirstChunk (result, " \t");
// basename
list<string> comp = splitstring (result, "/");
result = comp[size (comp) - 1]:"";
}
return result;
}
/**
* Considers the maps as structs and tests
* some of their fields for equality (conjunctively, short circuit).
* @param a one struct
* @param b other struct
* @param fields list of keys
* @return Do the maps have all the named fields equal?
*/
define boolean struct_match (map a, map b, list fields) ``{
// short circuit: use the _find_ builtin to get the mismatching key
any mismatch = find (any key, fields,
``( a[key]:nil != b[key]:nil ));
// mismatch is nil => they match
return mismatch == nil;
}
/**
* Considers the maps as structs and tests
* some of their fields for equality (conjunctively, short circuit).
* If a key is missing in either of the maps, it is considered as matching.
* <p> Used when merging autoyast items, to match only those fields that
* are specified in the profile. There, only one map is sparse.
* (the profile map)
* @param a one struct
* @param b other struct
* @param fields list of keys
* @return Do the maps have all named fields that are in both of them equal?
* @example match: $["a": 1, "b": 2, "c": 3], $["b": 2, "d": 4]
*/
define boolean struct_match_sparse (map a, map b, list fields) ``{
// short circuit: use the _find_ builtin to get the mismatching key
any mismatch = find (any key, fields,
``(
! ( a[key]:nil == b[key]:nil ||
!haskey (a, key) ||
!haskey (b, key))
));
// mismatch is nil => they match
return mismatch == nil;
}
/**
* Determine, if service package is installed.
* This function requires full configuration
* (like Inetd::netd_conf) and standalone map with service.
* Linear complexity (in the working config)
* @param netd_conf Full configuration
* @param s a @ref service
* @return match found
*/
define boolean isServiceMatchPresent (list<map <string, any> > netd_conf, map<string, any> s) ``{
map match = find (map<string, any> i, netd_conf, ``(
ServicesMatch (i, s)
));
return match != nil;
}
/**
* This function merges real xinetd configuration (read by agent) and
* available services packages generated for SuSE distribution
* This function is automaticaly calld by CreateTableData() if Inetd::configured_service
* is `xinetd.
* Adds those from default_conf that do not have a matching
* service in the working config.
* @param netd_conf not used in this function, but used for
* isServiceMatchPresent call.
* @param table_data Table data structure used as source data
* @return list New table data
*/
define list<term> AddNotInstalled (list<map <string, any> > netd_conf, list<term> table_data) ``{
//y2milestone("in function mergeXinetdConfs()");
list<map <string, any> > defaults = Inetd::default_conf;
integer index = 0;
foreach(map<string, any> line, defaults, ``{
if(! isServiceMatchPresent (netd_conf, line)) {
index = index + 1;
term entry = ServiceToTableItem (line, index);
table_data = add(table_data, entry);
}
});
return table_data;
}
/**
* @param service @ref service
* @param ni_index if nil, use iid as id, otherwise "NI"+ni_index
* @return main table item
*/
define term ServiceToTableItem (map service, integer ni_index) ``{
y2debug ("* %1", service["service"]:"");
string status_text = "";
string wait_text = "";
// determine service is enabled (enabled text)
string changed_text = (service["changed"]:false) ? "X" : "";
if (service["enabled"]:true) {
/* Translators: Service status: On = running, --- = stopped */
status_text = _("On");
}
else {
/* Translators: This string you can leave unchanged */
status_text = _("---");
}
// HACK:
// our data structures kinda suck, so we have no quick way of determining
// what package a service belongs to.
// But IsInstalled returns true for "" so we don't get to install an
// unknown package.
if (! IsInstalled (service["package"]:""))
{
/* Translators: This is used for status "Not Installed".
Please, make the
translation as short as possible. */
status_text = _("NI");
}
// determine wait mode (convert to string)
if (service["wait"]:true) {
wait_text = _("Yes");
}
else {
wait_text = _("No");
}
string sname = service["service"]:"";
string rpc_ver = service["rpc_version"]:"";
if (rpc_ver != "") {
sname = sname + "/" + rpc_ver;
}
string user_group = service["group"]:"";
if (user_group == "") {
user_group = service["user"]:"";
}
else {
// TODO switch to ":" as separator
user_group = service["user"]:"" + "." + user_group;
}
// create line for table structure
term entry = `item(
`id (
ni_index == nil ?
(service["iid"]:"0") :
("NI" + ni_index)
),
changed_text,
status_text,
sname,
service["socket_type"]:"",
service["protocol"]:"",
wait_text,
user_group,
service["server"]:"",
service["server_args"]:"");
return entry;
}
/**
* Sorts items for table of xinetd services
*
* @param list <term> unsorted_terms
* @return list <term> sorted_terms
*/
define list <term> SortTableData (list <term> unsorted_terms, integer sort_by) {
list <term> sorted_terms = [];
// string as the service name
// list of integers of position in unsorted list (the same service name can exist twice or more)
map <string, list <integer> > helper_sorting_map = $[];
integer position = 0;
string service_name = "";
foreach (term item, unsorted_terms, {
service_name = (string) item[sort_by]:"";
helper_sorting_map[service_name] = add(helper_sorting_map[service_name]:[], position);
position = position + 1;
});
// map is sorted by the string service name by defualt
foreach (string service_name, list <integer> term_ids, helper_sorting_map, {
foreach (integer term_id, term_ids, {
sorted_terms = add (sorted_terms, unsorted_terms[term_id]:`item(""));
});
});
return sorted_terms;
}
/**
* Converts configuration format from agent to table data structures
* @param netd_conf netd_conf handles whole configuration of configured service
* @return returnes table data
*/
define list<term> CreateTableData(list<map <string, any> > netd_conf) ``{
list<term> table_input = [];
foreach(map service, netd_conf, ``{
// service must be marked as nondeleted ("deleted" == false or "deleted" not exists)
if (! service["deleted"]:false) {
term entry = ServiceToTableItem (service, nil);
// add line to table structure
table_input = add(table_input, entry);
};
});
// now can do it for both superservers
// ... not yet
// because in the system data, we do not have the "package" field
table_input = AddNotInstalled (netd_conf, table_input);
// table_input = find out which are installed
// but that would require a better data model.
// let's try doing with the current one.
// OK, let's start with sorting the data by the service name
// term field '2' is the service name
table_input = SortTableData(table_input, 3);
return table_input;
}
/**
* Read user names from passwd.
* It does not get the NIS entries.
* "+" is filtered out.
* @return list users
*/
define list<string> CreateLocalUsersList() ``{
list<string> users = (list<string>) merge (
UsersCache::GetUsernames("local"),
UsersCache::GetUsernames("system")
);
users = sort(users);
y2debug("users: %1", users);
users = add(users, _("--default--"));
return users;
}
/**
* Read group names from group
* It does not get the NIS entries.
* "+" is filtered out.
* @return list groups
*/
define list<string> CreateLocalGroupsList() ``{
list<string> groups = (list<string>) merge (
UsersCache::GetGroupnames("local"),
UsersCache::GetGroupnames("system")
);
groups = sort(groups);
y2debug("groups: %1", groups);
groups = add(groups, _("--default--"));
return groups;
}
/**
* Find any service to be enabled
* If no found, return `no
* @param ready_conf ready_conf handles whole service configuration (Inetd::netd_conf)
* @return returnes if found `yes, otherwise `no
*/
define symbol IsAnyServiceEnabled(list<map <string, any> > ready_conf) ``{
symbol ret = `no;
foreach(map<string, any> line, ready_conf, ``{
if(line["deleted"]:false == false) {
if(line["enabled"]:false != false) {
ret = `yes;
}
}
});
return ret;
}
/**
* Do the services match?
* Considered fields:
* "script", "service", "protocol", "server" (or "server_args", if tcpd)
* The matching is sparse: a missing field in either map
* means the field is condidered as matching.
* @param a one map
* @param b other map
* @return match?
*/
define boolean ServicesMatch (map<string, any> a, map<string, any> b) ``{
if (struct_match_sparse (a, b, ["script", "service", "protocol"]))
{
// Compare whether the server matches
// Watch out for tcpd, use basenames
// because the 8.2 UI produced server="in.ftpd (ftpd)"
string a_serverbn = GetServerBasename ((string) (a["server"]:nil),
(string) (a["server_args"]:nil));
string b_serverbn = GetServerBasename ((string) (b["server"]:nil),
(string) (b["server_args"]:nil));
if (a_serverbn == nil ||
b_serverbn == nil ||
a_serverbn == b_serverbn)
{
return true;
}
}
return false;
}
/**
* Cache for @ref IsInstalled.
*/
map is_installed_cache = $[];
/**
* Clears cache for @ref IsInstalled .
* This is too wasteful. Later, when it works, optimize for single packages.
*/
define void IsInstalledClearCache () ``{
is_installed_cache = $[];
}
/**
* Queries RPM or autoyast list whether a package is installed.
* Results are cached in @ref is_installed_cache
* @param rpm eg. "finger-server", "" has special significance:
* package unknown, so it cannot be installed
* @return installed?
*/
define boolean IsInstalled (string rpm) ``{
boolean result = rpm == ""? true: is_installed_cache[rpm]:nil;
if (result == nil)
{
result = Package::Installed (rpm);
is_installed_cache = add (is_installed_cache, rpm, result);
}
y2debug ("%1: %2", rpm, result);
return result;
}
/* EOF */
}
ACC SHELL 2018