home *** CD-ROM | disk | FTP | other *** search
- /**
- * File:
- * RunlevelEd.ycp
- * Package:
- * System Services (Runlevel) (formerly known as Runlevel Editor)
- * Summary:
- * Data for configuration of services, input and output functions.
- *
- * Authors:
- * Martin Vidner <mvidner@suse.cz>
- * Petr Blahos <pblahos@suse.cz>
- * Martin Lazar <mlazar@suse.cz>
- *
- * $Id: RunlevelEd.ycp 33299 2006-10-10 09:39:23Z locilka $
- */
-
- {
- module "RunlevelEd";
- textdomain "runlevel";
-
- import "Service";
- import "Progress";
- import "Summary";
- import "Report";
- import "CommandLine";
-
- include "runlevel/toposort.ycp";
-
- /**
- * Proposal parameter: if it changes, we repropose
- */
- global boolean x11_selected = nil;
-
- /**
- * Like "requires" but in reverse direction.
- * Used for stopping and disabling services.
- */
- map<string, list<string> > what_requires = $[];
-
- /**
- * A graph where nodes are scripts or system facilities
- * but not normal facilities (ie. provides are solved).
- */
- map<string, list<string> > requires = $[];
-
- define void buildRequires ();
- define void addRequires (string service, list<string> req_facilities);
- define list reverse (list l);
- global define boolean StartContainsImplicitly (list<string> rls, string rl);
- define boolean ImplicitlySubset (list<string> rls_a, list<string> rls_b);
- define boolean subset (list a, list b);
-
- /**
- * @struct service
- * One service is described by such map: <pre>
- "servicename" : $[
- "defstart" : [ "2", "3", "5", ], // Default-Start comment
- "defstop" : [ "0", "1", "6", ], // Default-Stop comment
-
- // "should" dependencies (+) are filtered by addRequires
- "reqstart" : [ "$network", "portmap" ], // Required-Start comment
- "reqstop" : [ "$network", "portmap" ], // Required-Stop comment
-
- "shortdescription" : "text...", // Description comment
- "description" : "text...", // Description comment
-
- // which runlevels service is really started/stopped in
- // read from /etc/init.d/{rc?,boot}.d/* links
- //
- // Note that the boot process (init.d/boot.d) is considered
- // a "B" runlevel that is implicitly contained in the other runlevels.
- // Using
- // list st = services ["boot.local", "start"]:[]
- // contains (st, "3") // DON'T
- // results in false but that's probably not what you want.
- // Use
- // StartContainsImplicitly (st, "3")
- // which tests for "3" and "B".
- "start" : [ "3", "5", ],
- "stop" : [ "3", "5", ],
-
- "started" : 0, // return from rcservice status (integer)
-
- "dirty" : false, // was the entry changed?
- ]</pre>
- */
- //
- //
-
-
- /**
- * List of all services. Each item is a map described above.
- * @ref service
- */
- global map<string,map> services = $[];
-
- /**
- * List of all service names.
- * Filled by Read, used to get all services' status.
- */
- global list service_list = [];
-
- /**
- * Default runlevel (after boot)
- */
- global string default_runlevel = "";
-
- /**
- * Backup of default runlevel.
- */
- string default_orig = "";
-
- /**
- * List of all runlevels available in the system.
- */
- global list<string> runlevels = [];
-
- /**
- * Current runlevel
- */
- global string current = "";
-
- /* Dependency solving: */
- /**
- * ONLY ONE SCRIPT provides a facility in this model.
- * In SuSE packages, the only exception are sendmail and postfix
- * both providing sendmail but they cannot be installed together
- * anyway.
- * atd has Provides: at, so
- * what_provides["at"] == "atd";
- * Identity is not represented explicitly: ypbind has Provides: ypbind, but
- * haskey (what_provides, "ypbind") == false;
- */
- map what_provides = $[];
-
- /**
- * System facility definitions
- * "should" dependencies (+) are filtered by addRequires
- * /etc/insserv.conf:
- * system_requires["$network"] == ["network", "+pcmcia", "+hotplug"];
- */
- map<string, list<string> > system_requires = $[];
-
- /**
- * Read settings
- * @return success
- */
- global define boolean Read () ``{
- // progress caption
- Progress::Simple (_("Initializing system services (runlevel). Please wait..."), " ", 7, "");
- Progress::NextStep ();
- runlevels= (list<string>) SCR::Read (.init.scripts.runlevel_list);
- if (0 == size (runlevels))
- {
- runlevels = ["0", "1", "2", "3", "5", "6", "S", ];
- }
- Progress::NextStep ();
-
- current = (string) SCR::Read (.init.scripts.current_runlevel);
- Progress::NextStep ();
-
- //..
- default_runlevel = (string) SCR::Read (.init.scripts.default_runlevel);
- default_orig = default_runlevel;
- Progress::NextStep ();
-
- system_requires = (map<string, list<string> >) SCR::Read (.init.insserv_conf);
- Progress::NextStep ();
-
- map details = (map) SCR::Read (.init.scripts.runlevels);
- Progress::NextStep ();
- services = (map<string,map>) SCR::Read (.init.scripts.comments);
- Progress::NextStep ();
- services = (map<string, map>) mapmap (string k, map v, services, ``{
- foreach (string f, v["provides"]:[], ``{
- // identity implicit; only the first script provides a facility
- if (f != k && !haskey (what_provides, f))
- {
- what_provides[f] = k;
- }
- });
-
- service_list[size(service_list)] = k;
-
-
- // play tennis
- map second_service = details[k]:$[];
- v["start"] = second_service["start"]:[];
- v["stop"] = second_service["stop"]:[];
- return $[ k: v ];
- });
- buildRequires ();
- what_requires = ReverseGraph (requires);
- Progress::NextStep ();
- return true;
- }
-
- /**
- * If there's a dependency loop, dependency checking is disabled.
- */
- boolean dependencies_disabled = false;
- /**
- * Create requires from services, system_requires and what_provides.
- */
- define void buildRequires () ``{
- foreach (string service, map comments, services, ``{
- addRequires (service, (list<string>) (comments["reqstart"]:[]));
- });
- foreach (string sys_f, list<string> req, system_requires, ``{
- addRequires (sys_f, req);
- });
- }
- /**
- * Resolve provides, filter out "should" dependencies (+)
- * and add the requirements to "requires".
- * Missing services are not detected.
- * @param service a service
- * @param req_facilities its required facilities
- */
- define void addRequires (string service, list<string> req_facilities) ``{
- list<string> req_s = filter (string f, req_facilities,
- ``( substring (f, 0, 1) != "+"));
- req_s = maplist (string f, req_s, ``( what_provides[f]:f ));
- requires[service] = req_s;
- }
-
- /**
- * Resolve which services need to be enabled/disabled
- * @param service a service
- * @param enable enabling or disabling a service?
- * @return a list of services (excluding itself) required to start
- * a service (enable) or to be stopped because they require the
- * service (disable), ordered by their dependencies. Missing
- * services are included, system facilities excluded.<br>
- * If dependencies are disabled, returns an empty list, as if
- * there were no dependencies.
- */
- global define list<string> ServiceDependencies (string service,
- boolean enable) ``{
- if (dependencies_disabled)
- {
- return [];
- }
- // make a dependency subgraph
- map<string, list<string> > s_req = ReachableSubgraph (enable? requires: what_requires,
- service);
- y2debug ("DEPGRAPH %1: %2", service, s_req);
- // sort it
- list r = TopologicalSort (s_req);
- list<string> sorted = r[0]:[];
- list rest = r[1]:[];
- if (size (rest) > 0)
- {
- // TODO: localize the loop, disable it only locally
- // and say what scripts form it
- Report::Error (_("A dependency loop was detected.
- Further dependency checking will be disabled."));
- dependencies_disabled = true;
- }
-
- // filter system facilities
- sorted = filter (string f, sorted, ``(substring (f, 0, 1) != "$"));
- // remove the original service
- sorted = remove (sorted, 0);
- // reverse it so that the required services are first
- return (list<string>) reverse (sorted);
- }
-
- /**
- * Argh, not a builtin
- * @param l a list
- * @return reversed list
- */
- define list reverse (list l) ``{
- if (l == nil)
- {
- return nil;
- }
- list result = [];
- foreach (any item, l, ``{
- result = prepend (result, item);
- });
- return result;
- }
-
- /**
- * Gets a list of dependent services and a target state they
- * should be in. Filters out those that are already in the target
- * state.
- * If both init_time and run_time are on, a conjunction is needed.
- * @param svcs dependent services
- * @param rls used for init_time
- * @param enable on/off:
- * @param init_time enable/disable
- * @param run_time start/stop
- */
- global define list<string> FilterAlreadyDoneServices (list<string> svcs,
- list<string> rls,
- boolean enable,
- boolean init_time,
- boolean run_time) ``{
-
- // one: exactly one runlevel. nil means (disable) in all runlevels
- boolean one = rls != nil && size (rls) == 1;
- if (init_time && !enable &&
- rls != nil && !one)
- {
- // should not happen
- y2error ("Disabling in a nontrivial set of runlevels (%1) not implemented.", rls);
- return nil;
- }
- string rl = rls[0]:"";
-
- return filter (string service, svcs, ``{
- boolean all_ok = nil; // is the service in the target state?
-
- // run_time
- boolean run_ok = true;
- if (run_time)
- {
- boolean started =
- services[service, "started"]:-1 == 0 ||
- // boot scripts are always considered to be started,
- // even if they return 4 :(
- services[service, "defstart"]:[] == [ "B" ] ||
- // and while we're at it with kludges,
- // pretend nfs is running (ie. /usr is available)
- // because it reports 3 when no nfs imports are defined :(
- // TODO resolve it better!
- service == "nfs";
- run_ok = started == enable;
- }
-
- // init_time
- boolean init_ok = true;
- if (init_time)
- {
- list<string> start = services[service, "start"]:[];
-
- if (one)
- {
- init_ok = enable == StartContainsImplicitly (start, rl);
- }
- else
- {
- if (enable)
- {
- init_ok = ImplicitlySubset (rls, start);
- }
- else
- {
- // rls is nil, we only support disabling
- // in one or all runleves at once
- init_ok = start == [];
- }
- }
- }
-
-
- // keep it in the list if something needs to be done
- return !(init_ok && run_ok);
- });
- }
-
-
- /**
- * Is a service started in a runlevel, given the list of rulevels
- * it is started in?
- * This looks like a simple contains,
- * but "B" implicitly expands to all runlevels.
- * See also bug #17234.
- * @param rls runlevels the service is started in
- * @param rl which runlevel is tested
- * @return should it be running in rl?
- */
- global define boolean StartContainsImplicitly (list<string> rls,
- string rl) ``{
- return contains (rls, "B") || contains (rls, rl);
- }
- /**
- * Whether a set of runlevels is a subset of another set of runlevels.
- * But expands "B" to the whole set
- */
- define boolean ImplicitlySubset (list<string> rls_a,
- list<string> rls_b) ``{
- return contains (rls_b, "B") || subset (rls_a, rls_b);
- }
-
- /**
- * @param a a set
- * @param b a set
- * @return a \subseteq b
- */
- define boolean subset (list a, list b) ``{
- return size (union (a, b)) <= size (b);
- }
-
- /**
- * Set all dirty services as clean and tries to read
- * original "start"/"stop" for them.
- */
- global define void ClearServices () ``{
- services = (map<string, map>)mapmap (string k, map v, services, ``{
- if (v["dirty"]:false)
- {
- v["dirty"] = false;
- map r = (map) SCR::Read (.init.scripts.runlevel, k);
- r = r[k]:$[];
- v["start"] = r["start"]:[];
- v["stop"] = r["stop"]:[];
- }
- return $[k: v];
- });
- }
-
- /**
- * Is a service disabled?
- * Checks whether the default runlevel is in the list of runlevels
- * @param service service to check
- * @return boolean true if service is disabled
- */
- global define boolean isDisabled (map service) ``{
- return !contains(service["start"]:[], default_runlevel);
- }
-
- /**
- * Check for portmap. Portmap should be started if inetd, nfs,
- * nfsserver, nis, ... is started. This checks the dependency.
- * @return string name of the first enabled service that requires portmap
- */
- global define string CheckPortmap () ``{
- if (!isDisabled (services["portmap"]:$[])) // if portmap is enabled, there is no problem
- return nil;
- string req = nil;
- list in = [];
- foreach (string k, map v, services, ``{
- if (contains (v["reqstart"]:[], "portmap") && size (v["start"]:[]) > 0)
- {
- in = union (in, toset (v["start"]:[]));
- if (nil == req)
- req = k;
- }
- });
- return size (in) > 0 ? req : nil;
- }
-
- /**
- * Save changed services into proper runlevels. Save also changed
- * default runlevel.
- * @return success
- */
- global define boolean Write () ``{
- integer prsize = size (services);
- // progress caption
- Progress::Simple (_("Saving changes to runlevels."), " ", prsize + 1, "");
-
- if (default_runlevel != default_orig)
- SCR::Write (.init.scripts.default_runlevel, default_runlevel);
- Progress::NextStep ();
-
- map<string,map> failed = (map<string, map>)filter (string k, map v, services, ``{
- boolean fail = false;
- if (v["dirty"]:false)
- {
- // progress item, %1 is a service (init script) name
- Progress::Title (sformat (_("Service %1"), k));
- // save!
- list start = v["start"]:[];
- y2milestone ("Setting %1: %2", k, start);
- string verbose = sformat(_("Setting %1: %2"), k, start);
- CommandLine::PrintVerbose(verbose);
- fail = ! Service::Finetune (k, start);
- }
- else
- // progress item, %1 is a service (init script) name
- Progress::Title (sformat (_("Skipping service %1."), k));
- Progress::NextStep ();
- return fail;
- });
- Progress::NextStep ();
- string failed_s = mergestring ((list<string>) maplist (string k, any v, failed, ``(k)), ", ");
- if (size (failed_s) > 0)
- {
- Report::Error (sformat (_("Failed services: %1."), failed_s));
- return false;
- }
- return true;
- }
-
- /**
- * Were some settings changed?
- * @return true if yes
- */
- global define boolean isDirty () ``{
- if (default_runlevel != default_orig)
- return true;
-
- boolean dirty = false;
- foreach (string k, map v, services, ``{
- if (dirty)
- {
- return ;
- }
- if (v["dirty"]:false)
- {
- dirty = true;
- }
- });
- return dirty;
- }
-
- /**
- * Returns true if the settings were modified
- * @return settings were modified
- */
- global boolean GetModified () {
- return isDirty ();
- }
-
- /**
- * Function sets an internal variable indicating that any
- * settings were modified to "true".
- * Used for autoinst cloning.
- */
- global void SetModified () {
- // Make sure GetModified will return true
- default_orig = "---";
- // maybe we should also touch dirty for all services,
- // but that depends on what autoinst Clone really wants
- }
-
- /**
- * Export user settings.
- * @return user settings:<pre>$[
- * "services": $[ map of dirty services ],
- * "default": the default runlevel, if changed,
- *]</pre>
- */
- global define map Export () ``{
- y2debug("services: %1", services);
- map<string,map> svc = (map<string, map>)filter (string k, map v, services, ``{
- return v["dirty"]:false;
- });
- list tmp_services = maplist(string service_name, map service_data, svc, ``{
- string service_start = mergestring(service_data["start"]:[], " ");
- string service_stop = mergestring(service_data["stop"]:[], " ");
-
- map service_map = $[];
- service_map["service_name"] = service_name;
- if (size(service_start) > 0 )
- {
- service_map["service_start"] = service_start;
- }
- if (size(service_stop) > 0 )
- {
- service_map["service_stop"] = service_stop;
- }
-
- return (service_map);
- });
- map ret = $[];
- if (size(tmp_services)>0)
- {
- ret = $[ "services" : tmp_services ];
- }
- if ( default_runlevel != "")
- {
- ret["default"] = default_runlevel;
- }
- return ret;
- }
- /**
- * Import user settings
- * @param s user settings
- * @see Export
- * @return success state
- */
- global define boolean Import (map s) ``{
- runlevels = (list<string>) SCR::Read (.init.scripts.runlevel_list);
- if (0 == size (runlevels))
- {
- runlevels = ["0", "1", "2", "3", "5", "6", "S", ];
- }
-
- //..
- default_runlevel = (string) SCR::Read (.init.scripts.default_runlevel);
- default_orig = default_runlevel;
-
- // and finaly process map being imported
- list<map> new = s["services"]:[];
- map<string,map> tmp_services = (map<string, map>)listmap(map service, new, ``{
- string name = service["service_name"]:"";
- list stop = [];
- list start = [];
- if (haskey(service, "service_status"))
- {
- if (service["service_status"]:"" == "enable")
- {
- map info = Service::Info(name);
- y2milestone("service info for %1: %2", name, info);
- start = info["defstart"]:[];
- stop = info["defstop"]:[];
- }
- else if (service["service_status"]:"" == "disable")
- {
- start = [];
- stop = [];
- }
- }
- else
- {
- start = splitstring(service["service_start"]:"", " ");
- stop = splitstring(service["service_stop"]:"", " ");
- }
-
- map service_map = $[];
- if (size(start) > 0 )
- service_map["start"] = start;
- if (size(stop) > 0 )
- service_map["stop"] = stop;
- return($[name:service_map]);
- });
-
- if (size (tmp_services) > 0)
- {
- foreach (string k, map v, tmp_services, ``{
- if (nil == services[k]:nil)
- {
- y2milestone ("Service %1 is not installed on target system, adding it by hand.", k);
- }
- v["dirty"] = true;
- services[k] = v;
- });
- }
- else
- services = $[];
- // default
- if (haskey (s, "default"))
- {
- default_runlevel = s["default"]:"";
- default_orig = "---";
- }
- return true;
- }
-
- /**
- * Returns textual runlevel description.
- * Descriptions are hard-coded in ycp script.
- * @param rl Runlevel to check.
- * @return string Description.
- */
- global define string getRunlevelDescr (string rl) ``{
- map<string, string> descr = $[
- // descriptions of runlevels. there must be number: description
- // number is runlevel name
- // runlevel description
- "0" : _("0: System halt"),
- // runlevel description
- "1" : _("1: Single user mode"),
- // runlevel description
- "2" : _("2: Local multiuser without remote network"),
- // runlevel description
- "3" : _("3: Full multiuser with network"),
- // runlevel description
- "4" : _("4: User defined"),
- // runlevel description
- "5" : _("5: Full multiuser with network and display manager"),
- // runlevel description
- "6" : _("6: System reboot"),
- // runlevel description
- // internal one: without a number
- "" : _("Unchanged"),
- ];
- return descr[rl]:rl;
- }
-
- /**
- * @return Html formatted summary for the installation proposal
- */
- global define string ProposalSummary() ``{
- string sum = "";
- // summary header
- sum = Summary::OpenList(sum);
- sum = Summary::AddListItem(sum, getRunlevelDescr (default_runlevel));
- sum = Summary::CloseList(sum);
-
- return sum;
- }
-
- /**
- * @return Html formatted configuration summary
- */
- global define string Summary()
- ``{
- string sum = "";
- sum = Summary::AddHeader(sum, _("Default Runlevel"));
- sum = Summary::AddLine(sum, getRunlevelDescr (default_runlevel));
- // summary header
- sum = Summary::AddHeader(sum, _("Services"));
-
- if (size(services)>0) {
- sum = Summary::OpenList(sum);
- foreach(string k, map v, services, ``{
- if (v["dirty"]:false)
- {
- string item = sformat (
- // summary item: %1 service name,
- // %2, %3 list of runlevels it starts/stops in
- _("<p><b>%1</b><br> Start: %2</p>"),
- k,
- mergestring(v["start"]:[], " ")
- );
- sum = Summary::AddListItem(sum, item );
- }
- });
- sum = Summary::CloseList(sum);
- }
- else
- {
- sum = Summary::AddLine(sum, Summary::NotConfigured());
- }
- return sum;
- }
-
- // visualization helper
-
- /**
- * A buffer for @ref sprint
- */
- string sprint_buffer = "";
-
- /**
- * String print
- * @param s a string to add to @ref sprint_buffer
- */
- define void sprint (string s) ``{
- sprint_buffer = sprint_buffer + s;
- }
-
- /**
- * @return a graphviz graph of the service dependencies
- */
- global define string DotRequires () ``{
- map in_attr = $[
- "$remote_fs": "[color=yellow, minlen=2]",
- "$local_fs": "[color=green, minlen=2]",
- "$network": "[color=magenta, minlen=2]",
- "$syslog": "[color=cyan, minlen=2]",
- ];
- sprint_buffer = "";
- sprint ("digraph services {\n");
- sprint ("\trankdir=LR;\n");
- sprint ("\t\"!missing\"[rank=max];\n");
- sprint ("\t\"$syslog\" -> \"$network\" [style=invis, minlen=10];\n");
- sprint ("\t\"$remote_fs\" -> \"$syslog\" [style=invis, minlen=5];\n");
- foreach (string n, list<string> e, requires, ``{
- foreach (string target, e, ``{
- string attr = in_attr[target]:"";
- sprint (sformat ("\t\"%1\" -> \"%2\"%3;\n", n, target, attr));
- });
- });
- sprint ("}\n");
- return sprint_buffer;
- }
-
- /*** LiMaL API PART I. - Runlevels in /etc/inittab File ***/
-
- global string GetCurrentRunlevel() {
- return current == "" ? "unknown" : current;
- }
- global string GetDefaultRunlevel() {
- return default_runlevel;
- }
-
- global integer SetDefaultRunlevel(string rl) {
- default_runlevel = rl;
- return 0;
- }
-
- global define list<string> GetAvailableRunlevels() {
- return runlevels;
- }
-
- /*** LiMaL API PART II. - Files and/or Symlinks in /etc/init.d and /etc/rc?.d ***/
- global boolean ServiceAvailable(string service_name)
- {
- return (boolean)SCR::Read(.init.scripts.exists, service_name);
- }
-
- global list<string> GetAvailableServices(boolean simple)
- {
- list<string> s = (list<string>)maplist(string service_name, map opts, RunlevelEd::services, {return service_name;});
- if (simple) {
- s = filter(string service_name, s, {return !contains(services[service_name,"defstart"]:[], "B");});
- }
- return s;
- }
-
- global list<string> GetServiceCurrentStartRunlevels(string service_name)
- {
- return services[service_name,"start"]:[];
- }
-
- global list<string> GetServiceCurrentStopRunlevels(string service_name)
- {
- return services[service_name,"stop"]:[];
- }
-
- /*** LiMaL API PART III. - LSB Comments in Init Scripts ***/
-
- //string GetServiceLSBCommentValue(string service_name, string key); // return particular LSB comment
- //list_of_strings GetServiceLSBCommentKeys(string service_name); // return list of presented LSB comment keys
-
- global list<string> GetServiceDefaultStartRunlevels(string service_name)
- {
- return services[service_name,"defstart"]:[];
- }
-
- global list<string> GetServiceDefaultStopRunlevels(string service_name)
- {
- return services[service_name,"defstop"]:[];
- }
-
- //boolean GetServiceDefaultEnabled(string service_name); // not in LSB?
-
- global string GetServiceShortDescription(string service_name)
- {
- return services[service_name, "shortdescription"]:"";
- }
-
- global string GetServiceDescription(string service_name)
- {
- return services[service_name, "description"]:"";
- }
-
- //list_of_strings GetServiceProvides(string service_name);
- //list_of_strings GetServiceRequiredStart(string service_name);
- //list_of_strings GetServiceRequiredStop(string service_name);
- //list_of_strings GetServiceShouldStart(string service_name);
- //list_of_strings GetServiceShouldStop(string service_name);
-
- /*** LiMaL API PART V. - Installation and Removal of init.d Files ***/
-
- /**
- * Enable specified service, and all required services.
- * @param service service name
- * @param rls runlevels to enable in or nil for default runlevels
- * @return 0 = ok, 1 = service not found
- */
- global integer ServiceInstall(string service, list<string> rls)
- {
- if (!haskey(services, service))
- return 1; // service not found
-
- if (rls == nil)
- rls = GetServiceDefaultStartRunlevels(service);
-
- list<string> dep_s = RunlevelEd::ServiceDependencies(service, true);
- dep_s = RunlevelEd::FilterAlreadyDoneServices(dep_s, rls, true, true, false);
- if (dep_s != nil) {
- foreach(string i, dep_s, {
- list<string> default_rls = GetServiceDefaultStartRunlevels(i);
- if (contains(default_rls, "B")) {
- services[i,"start"] = union(["B"], services[service,"start"]:[]);
- } else {
- services[i,"start"] = union(rls, services[service,"start"]:[]);
- }
- services[i,"dirty"] = true;
- });
- }
- services[service,"start"] = union(rls, services[service,"start"]:[]);
- services[service,"dirty"] = true;
-
- return 0;
- }
-
-
- /**
- * Disable specified service, and all dependence services.
- * @param service service name
- * @param rls runlevels to disable in or nil for default runlevels
- * @return 0 = ok
- */
- global integer ServiceRemove(string service, list<string> rls)
- {
- if (!haskey(services, service))
- return 0; // service not found (no error)
-
- if (rls == nil) {
- rls = GetServiceDefaultStartRunlevels(service);
- }
- list<string> dep_s = RunlevelEd::ServiceDependencies(service, false);
- foreach(string rl, (list<string>)union(rls, ["B"]), {
- list<string> dep_s1 = RunlevelEd::FilterAlreadyDoneServices(dep_s, [rl], false, true, false);
- if (dep_s1 != nil) {
- foreach(string j, dep_s, {
- services[j,"start"] = filter(string i, services[j,"start"]:[], {return !contains(rls, i);});
- services[j,"dirty"] = true;
- });
- }
- });
- services[service,"start"] = filter(string i, services[service,"start"]:[], {return !contains(rls, i);});
- services[service,"dirty"] = true;
-
- return 0;
- }
-
- /**
- * Returns items for default runlevel combo box.
- * (Excludes 0, 1, 6, S and B)
- * @param mode if `auto, adds Unchanged. if `proposal, only 2, 3 and 5
- * @return list List of items. Default is selected.
- */
- global list getDefaultPicker (symbol mode) ``{
- list items = [];
- list<string> rls = RunlevelEd::runlevels;
- if (mode == `auto)
- {
- rls = prepend (rls, "");
- }
- else if (mode == `proposal)
- {
- // We could read the list from SCR (#37071) but
- // inittab in the inst-sys is pre-lsb so we have to override it
- rls = ["2", "3", "5"];
- }
-
- foreach (string i, rls, ``{
- // which ones to avoid: #36110
- if ("0" != i && "1" != i && "6" != i && "S" != i && "B" != i)
- {
- items[size(items)] = `item (`id (i),
- RunlevelEd::getRunlevelDescr (i),
- i == RunlevelEd::default_runlevel);
- }
- });
- return items;
- }
-
-
- }
-