home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / modules / Service.ycp < prev    next >
Text File  |  2006-11-29  |  13KB  |  473 lines

  1. /**
  2.  * File:    modules/Service.ycp
  3.  * Package:    yast2
  4.  * Summary:    Service manipulation
  5.  * Authors:    Martin Vidner <mvidner@suse.cz>
  6.  *        Petr Blahos <pblahos@suse.cz>
  7.  *        Michal Svec <msvec@suse.cz>
  8.  *        Lukas Ocilka <locilka@suse.cz>
  9.  * Flags:    Stable
  10.  *
  11.  * $Id: Service.ycp 31242 2006-06-01 12:59:16Z locilka $
  12.  *
  13.  * Functions for service (init script) handling used by other modules.
  14.  */
  15.  
  16. {
  17.  
  18. module "Service";
  19. textdomain "base";
  20.  
  21. /***
  22.  * Services Manipulation
  23.  */
  24.  
  25. /**
  26.  * @struct service
  27.  * One service is described by such map: <pre>
  28.   "servicename" : $[
  29.     "defstart" : [ "2", "3", "5", ], // Default-Start comment
  30.     "defstop"  : [ "0", "1", "6", ], // Default-Stop  comment
  31.  
  32.     "reqstart" : [ "$network", "portmap" ], // Required-Start comment
  33.     "reqstop"  : [ "$network", "portmap" ], // Required-Stop  comment
  34.  
  35.     "description" : "text...",       // Description comment
  36.  
  37.     "start" : [ "3", "5", ], // which runlevels service is really started/stopped in
  38.     "stop"  : [ "3", "5", ], // read from /etc/init.d/rc?.d/* links
  39.  
  40.     "started" : 0, // return from rcservice status (integer)
  41.  
  42.     "dirty" : false, // was the entry changed?
  43.   ]</pre>
  44.  */
  45.  
  46. /**
  47.  * Script location
  48.  */
  49. string init_d = "/etc/init.d";
  50.  
  51. /**
  52.  * After a function returns an error, this holds an error message,
  53.  * including insserv stderr and possibly containing newlines.
  54.  *
  55.  * Set by
  56.  * checkExists: [Full]Info, Status, Enabled, Adjust, Finetune
  57.  *
  58.  * Never cleared.
  59.  */
  60. string error_msg = "";
  61.  
  62. /**
  63.  * Check that a service exists.
  64.  * If not, set error_msg.
  65.  * @param name service name without a path, eg. nfsserver
  66.  * @return Return true if the service exists.
  67.  */
  68. define boolean checkExists (string name) {
  69.     if(name == nil || name == "") {
  70.     // Error message.
  71.     // %1 is a name of an init script in /etc/init.d,
  72.     // eg. nfsserver
  73.     error_msg = sformat (_("Empty service name: %1."), name);
  74.     y2error(1, error_msg);
  75.     return false;
  76.     }
  77.     if(! (boolean) SCR::Read(.init.scripts.exists, name)) {
  78.     // Error message.
  79.     // %1 is a name of an init script in /etc/init.d,
  80.     // eg. nfsserver
  81.     error_msg = sformat (_("Service %1 does not exist."), name);
  82.     y2error (1, error_msg);
  83.     return false;
  84.     }
  85.     return true;
  86. }
  87.  
  88. /**
  89.  * Get service info without peeking if service runs.
  90.  * @param name name of the service
  91.  * @return Service information or empty map ($[])
  92.  */
  93. global define map Info (string name) {
  94.     if(!checkExists (name)) return $[];
  95.     map read = (map) SCR::Read (.init.scripts.runlevel, name);
  96.     map detail = read[name]:$[];
  97.     read = (map) SCR::Read (.init.scripts.comment, name);
  98.     map service = read[name]:$[];
  99.     return add (
  100.     add (service, "start", detail["start"]:[]),
  101.     "stop", detail["stop"]:[]);
  102. }
  103.  
  104. /**
  105.  * Get service status.
  106.  *
  107.  * The status is the output from "service status".
  108.  * It should conform to LSB. 0 means the service is running.
  109.  * @param name name of the service
  110.  * @return init script exit status or -1 if it does not exist
  111.  */
  112. global define integer Status (string name) {
  113.     if(!checkExists (name)) return -1;
  114.     return (integer) SCR::Execute (.target.bash, sformat ("%2/%1 status", name, init_d), $["TERM":"raw"]);
  115. }
  116.  
  117. /**
  118.  * Get service info and find out whether service is running.
  119.  * @param name name of the service
  120.  * @return service map or empty map ($[])
  121.  */
  122. global define map FullInfo (string name) {
  123.     if(!checkExists (name)) return $[];
  124.     return add (Info (name), "started", Status (name));
  125. }
  126.  
  127. /**
  128.  * Call insserv -r and record errors.
  129.  * Does not check if it exists
  130.  * @param name service name
  131.  * @param force pass "-f" to insserv (workaround for #17608, #27370)
  132.  * @return success state
  133.  */
  134. define boolean serviceDisable (string name, boolean force) {
  135.     map ret = (map)SCR::Execute (.target.bash_output,
  136.                 sformat ("/sbin/insserv -r%3 %2/%1",
  137.                      name, init_d, force? "f": ""));
  138.     if (0 != ret["exit"]:-1)
  139.     {
  140.     // Error message.
  141.     // %1 is a name of an init script in /etc/init.d,
  142.     // Disabling means that the service should not start
  143.     // in appropriate runlevels, eg. at boot time.
  144.     // %2 is the stderr output of insserv(8)
  145.     error_msg = sformat(_("Unable to disable service %1:\n%2"),
  146.                 name, ret["stderr"]:"");
  147.     // the user is two levels up
  148.     y2error (2, error_msg);
  149.     return false;
  150.     }
  151.     return true;
  152. }
  153.  
  154. /**
  155.  * Adjust runlevels in which the service runs.
  156.  * @param name service name
  157.  * @param action "disable" -- remove links, "enable" -- if there are
  158.  *    no links, set default, otherwise do nothing, "default" -- set
  159.  *    defaults.
  160.  * @return success state
  161.  */
  162. global define boolean Adjust (string name, string action) {
  163.     if (! checkExists (name))
  164.     {
  165.     return false;
  166.     }
  167.     map service = Info (name);
  168.     if ("disable" == action)
  169.     {
  170.     if (size (service["start"]:[]) != 0)
  171.     {
  172.         return serviceDisable (name, false);
  173.     }
  174.     return true;
  175.     }
  176.     if (("default" == action) || ("enable" == action))
  177.     {
  178.     if ("enable" == action && size (service["start"]:[]) != 0)
  179.     {
  180.         // nothing to do
  181.         return true;
  182.     }
  183.     else
  184.     {
  185.         map ret = (map)SCR::Execute (.target.bash_output,
  186.                     sformat ("/sbin/insserv -d %2/%1",
  187.                          name, init_d));
  188.         if (0 != ret["exit"]:-1)
  189.         {
  190.         // Error message.
  191.         // %1 is a name of an init script in /etc/init.d,
  192.         // Enabling means that the service should start
  193.         // in appropriate runlevels, eg. at boot time.
  194.         // %2 is the stderr output of insserv(8)
  195.         error_msg = sformat(_("Unable to enable service %1:\n%2"),
  196.                     name, ret["stderr"]:"");
  197.         y2error (1, error_msg);
  198.         return false;
  199.         }
  200.     }
  201.     return true;
  202.     }
  203.     // not translated
  204.     error_msg = sformat ("Invalid parameter: %1", action);
  205.     y2internal (1, error_msg);
  206.     return false;
  207. }
  208.  
  209. /**
  210.  * Set service to run in selected runlevels.
  211.  * @param name name of service to adjust
  212.  * @param rl list of runlevels in which service should start
  213.  * @return success state
  214.  */
  215. global define boolean Finetune (string name, list rl) {
  216.     if (! checkExists (name))
  217.     {
  218.     return false;
  219.     }
  220.  
  221.     // Force because of #27370:
  222.     // RunlevelEd::Write has already solved the dependencies
  223.     // and calls us only once for each modified service.
  224.     // In general we cannot do it with dependencies in a single pass.
  225.  
  226.     string rls = mergestring ((list<string>)rl, ",");
  227.     // we must remove it first because insserv start=... adds
  228.     // runlevels, not replace runlevels!!
  229.     if (! serviceDisable (name, true))
  230.     {
  231.     return false;
  232.     }
  233.  
  234.     if (rls != "")
  235.     {
  236.     map ret = (map)SCR::Execute (.target.bash_output,
  237.                 sformat ("/sbin/insserv -f %2/%1,start=%3",
  238.                      name, init_d, rls));
  239.     if (0 != ret["exit"]:-1)
  240.     {
  241.         // Error message.
  242.         // %1 is a name of an init script in /etc/init.d,
  243.         // Enabling means that the service should start
  244.         // in appropriate runlevels, eg. at boot time.
  245.         // %2 is the stderr output of insserv(8)
  246.         // %3 is a comma separated list of runlevels
  247.         error_msg = sformat(_("Unable to enable service %1 in runlevels %2:\n%3"),
  248.                 name, rls, ret["stderr"]:"");
  249.         y2error (1, error_msg);
  250.         return false;
  251.     }
  252.     }
  253.     return true;
  254. }
  255.  
  256. /**
  257.  * Check if service is enabled
  258.  *
  259.  * Returns true if any link in /etc/init.d/rc?.d/ exists for this
  260.  * script. If service does not exist, logs an error.
  261.  *
  262.  * @param name service name
  263.  * @return true if service is set to run in any runlevel
  264.  */
  265. global define boolean Enabled (string name) {
  266.     if(!checkExists (name)) return false;
  267.     map<string, any> details = (map<string, any>) SCR::Read (.init.scripts.runlevel, name);
  268.     map<string, any> detail  = (map<string, any>) details[name]:$[];
  269.     return size(detail["start"]:[]) != 0;
  270. }
  271.  
  272. /**
  273.  * Run init script.
  274.  * @param name init service name
  275.  * @param param init script argument
  276.  * @return integer exit value
  277.  */
  278. global define integer RunInitScript (string name, string param) {
  279.     y2milestone("Running service initscript %1 %2", name, param);
  280.     return (integer) SCR::Execute (.target.bash,
  281.         sformat ("%2/%1 %3", name, init_d, param),
  282.         $[ "TERM" : "raw"]);
  283. }
  284.  
  285.  
  286. /* Time out for background agent - init script run */
  287. integer script_time_out = 60000;
  288. integer sleep_step = 20;
  289.  
  290. /**
  291.  * Run init script with a time-out.
  292.  * @param name init service name
  293.  * @param param init script argument
  294.  * @return integer exit value
  295.  */
  296. global define integer RunInitScriptWithTimeOut (string name, string param) {
  297.     y2milestone("Running service initscript %1 %2", name, param);
  298.     string command = sformat ("TERM=dumb %2/%1 %3", name, init_d, param);
  299.  
  300.     // default return code
  301.     integer return_code = nil;
  302.  
  303.     // starting the process
  304.     boolean started = (boolean)SCR::Execute(.background.run_output_err, command);
  305.     if (!started) {
  306.     y2error("Cannot run '%1'", command);
  307.     return return_code;
  308.     }
  309.     y2debug("Running: %1", command);
  310.  
  311.     list<string> script_out = [];
  312.     integer time_spent = 0;
  313.     boolean cont_loop = true;
  314.  
  315.     // while continuing is needed and while it is possible
  316.     while (cont_loop && ((boolean) SCR::Read(.background.output_open))) {
  317.     if (time_spent >= script_time_out) {
  318.         y2error("Command '%1' timed-out after %2 mces", command, time_spent);
  319.         cont_loop = false;
  320.     }
  321.  
  322.     // sleep a little while
  323.     time_spent = time_spent + sleep_step;
  324.     sleep(sleep_step);
  325.     }
  326.     
  327.     // fetching the return code if not timed-out
  328.     if (cont_loop) {
  329.     return_code = (integer) SCR::Read(.background.status);
  330.     }
  331.  
  332.     y2milestone("Time spent: %1 msecs, retcode: %2", time_spent, return_code);
  333.  
  334.     // killing the process (if it still runs)
  335.     SCR::Execute(.background.kill, "");
  336.  
  337.     return return_code;
  338. }
  339.  
  340. string lang = nil;
  341.  
  342. /**
  343.  * Run init script and return output
  344.  *
  345.  * Run init script and also return its output (stdout and stderr merged).
  346.  * @param name init service name
  347.  * @param param init script argument
  348.  * @return A map of $[ "stdout" : "...", "stderr" : "...", "exit" : int]
  349.  */
  350. global define map RunInitScriptOutput (string name, string param) {
  351.     map env = $["TERM": "raw"];
  352.  
  353.     // encoding problems - append .UTF-8 to LANG
  354.     if (lang == nil)
  355.     {
  356.     map<string, any> ex = (map<string, any>) SCR::Execute (.target.bash_output, "echo -n $LANG");
  357.     lang = ex["stdout"]:"";
  358.     list ll = splitstring (lang, ".");
  359.     lang = ll[0]:"";
  360.     if (lang != "")
  361.     {
  362.         lang = lang + ".UTF-8";
  363.     }
  364.     y2debug ("LANG: %1", lang);
  365.     }
  366.     if (lang != "")
  367.     {
  368.     env = add (env, "LANG", lang);
  369.     }
  370.  
  371.     // looks like a bug in bash...
  372.     string locale_debug = "";
  373.     // locale_debug = "; ls /nono 2>&1; /usr/bin/locale; /usr/bin/env";
  374.  
  375.     return (map)SCR::Execute (.target.bash_output,
  376.              sformat ("%2/%1 %3 2>&1", name, init_d, param)
  377.              + locale_debug,
  378.              env);
  379. }
  380.  
  381. /**
  382.  * Enable service
  383.  * @param service service to be enabled
  384.  * @return true if operation is  successful
  385.  */
  386. global define boolean Enable(string service) {
  387.     if(!checkExists(service)) return false;
  388.     y2milestone("Enabling service %1", service);
  389.     return Adjust(service, "enable");
  390. }
  391.  
  392. /**
  393.  * Disable service
  394.  * @param service service to be disabled
  395.  * @return true if operation is  successful
  396.  */
  397. global define boolean Disable(string service) {
  398.     if(!checkExists(service)) return false;
  399.     y2milestone("Disabling service %1", service);
  400.     return Adjust(service, "disable");
  401. }
  402.  
  403. /**
  404.  * Start service
  405.  * @param service service to be started
  406.  * @return true if operation is  successful
  407.  */
  408. global define boolean Start(string service) {
  409.     if(!checkExists(service)) return false;
  410.     integer ret = nil;
  411.     y2milestone("Starting service %1", service);
  412.     ret = RunInitScript(service, "start");
  413.     y2debug("ret=%1", ret);
  414.     return ret == 0;
  415. }
  416.  
  417. /**
  418.  * Restart service
  419.  * @param service service to be restarted
  420.  * @return true if operation is  successful
  421.  */
  422. global define boolean Restart(string service) {
  423.     if(!checkExists(service)) return false;
  424.     integer ret = nil;
  425.     y2milestone("Restarting service %1", service);
  426.     ret = RunInitScript(service, "restart");
  427.     y2debug("ret=%1", ret);
  428.     return ret == 0;
  429. }
  430.  
  431. /**
  432.  * Reload service
  433.  * @param service service to be reloaded
  434.  * @return true if operation is  successful
  435.  */
  436. global define boolean Reload(string service) {
  437.     if(!checkExists(service)) return false;
  438.     integer ret = nil;
  439.     y2milestone("Reloading service %1", service);
  440.     ret = RunInitScript(service, "reload");
  441.     y2debug("ret=%1", ret);
  442.     return ret == 0;
  443. }
  444.  
  445. /**
  446.  * Stop service
  447.  * @param service service to be stopped
  448.  * @return true if operation is  successful
  449.  */
  450. global define boolean Stop(string service) {
  451.     if(!checkExists(service)) return false;
  452.     integer ret = nil;
  453.     y2milestone("Stopping service %1", service);
  454.     ret = RunInitScript(service, "stop");
  455.     y2debug("ret=%1", ret);
  456.     return ret == 0;
  457. }
  458.  
  459. /**
  460.  * Error Message
  461.  *
  462.  * If a Service function returns an error, this function would return
  463.  * an error message, including insserv stderr and possibly containing
  464.  * newlines.
  465.  * @return error message from the last operation
  466.  */
  467. global define string Error() {
  468.     return error_msg;
  469. }
  470.  
  471. /* EOF */
  472. }
  473.