home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / system-tools-backends-2.0 / scripts / Init / Services.pm next >
Encoding:
Perl POD Document  |  2009-04-09  |  30.7 KB  |  1,372 lines

  1. #-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  
  3. # Functions for manipulating system services, like daemons and network.
  4. #
  5. # Copyright (C) 2002 Ximian, Inc.
  6. #
  7. # Authors: Carlos Garnacho Parro <garparr@teleline.es>,
  8. #          Hans Petter Jansson <hpj@ximian.com>,
  9. #          Arturo Espinosa <arturo@ximian.com>
  10. #
  11. # This program is free software; you can redistribute it and/or modify
  12. # it under the terms of the GNU Library General Public License as published
  13. # by the Free Software Foundation; either version 2 of the License, or
  14. # (at your option) any later version.
  15. #
  16. # This program is distributed in the hope that it will be useful,
  17. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. # GNU Library General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU Library General Public License
  22. # along with this program; if not, write to the Free Software
  23. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  24.  
  25. package Init::Services;
  26.  
  27. my $SERVICE_START = 0;
  28. my $SERVICE_STOP  = 1;
  29.  
  30. use Init::ServicesList;
  31. use Utils::Report;
  32.  
  33. sub get_runlevels
  34. {
  35.   my (%dist_map, %runlevels);
  36.   my ($desc, $distro);
  37.  
  38.   %dist_map =
  39.     (
  40.      "redhat-6.2"       => "redhat-6.2",
  41.      "redhat-7.0"       => "redhat-6.2",
  42.      "redhat-7.1"       => "redhat-6.2",
  43.      "redhat-7.2"       => "redhat-6.2",
  44.      "redhat-7.3"       => "redhat-6.2",
  45.      "redhat-8.0"       => "redhat-6.2",
  46.      "mandrake-9.0"     => "redhat-6.2",
  47.      "conectiva-9"      => "redhat-6.2",
  48.      "debian-3.0"       => "redhat-6.2",
  49.      "debian-3.1"       => "redhat-6.2",
  50.      "debian-4.0"       => "redhat-6.2",
  51.      "debian-5.0"       => "redhat-6.2",
  52.      "debian-testing"   => "redhat-6.2",
  53.      "ubuntu-7.04"      => "redhat-6.2",
  54.      "suse-9.0"         => "redhat-6.2",
  55.      "pld-1.0"          => "redhat-6.2",
  56.      "vine-3.0"         => "redhat-6.2",
  57.      "slackware-9.1.0"  => "freebsd-5",
  58.      "gentoo"           => "gentoo",
  59.      "archlinux"        => "freebsd-5",
  60.      "freebsd-5"        => "freebsd-5",
  61.      "solaris-2.11"     => "freebsd-5",
  62.     );
  63.  
  64.   %runlevels=
  65.     (
  66.      "redhat-6.2"      => [ "0", "1", "2", "3", "4", "5", "6" ],
  67.      "gentoo"          => &get_gentoo_runlevels (),
  68.      "freebsd-5"       => [ "default" ],
  69.     );
  70.  
  71.   $distro = $dist_map{$Utils::Backend::tool{"platform"}};
  72.   $desc = $runlevels{$distro};
  73.  
  74.   return $desc;
  75. }
  76.  
  77. # This function gets the runlevel that is in use
  78. sub get_sysv_default_runlevel
  79. {
  80.     my (@arr);
  81.     @arr = split / /, `/sbin/runlevel` ;
  82.   chomp $arr[1];
  83.  
  84.     return $arr[1];
  85. }
  86.  
  87. sub get_default_runlevel
  88. {
  89.   my $type = &get_init_type ();
  90.  
  91.   return "default" if ($type eq "gentoo" || $type eq "rcng" || $type eq "bsd" || $type eq "smf");
  92.   return &get_sysv_default_runlevel ();
  93. }
  94.  
  95. sub get_sysv_paths
  96. {
  97.   my %dist_map =
  98.     (
  99.      # gst_dist => [rc.X dirs location, init.d scripts location, relative path location]
  100.      "redhat-6.2"     => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  101.      "redhat-7.0"     => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  102.      "redhat-7.1"     => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  103.      "redhat-7.2"     => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  104.      "redhat-7.3"     => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  105.      "redhat-8.0"     => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  106.      "mandrake-9.0"   => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  107.      "yoper-2.2"      => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  108.      "conectiva-9"    => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  109.      "debian-3.0"     => ["$gst_prefix/etc",      "$gst_prefix/etc/init.d",      "../init.d"],
  110.      "debian-3.1"     => ["$gst_prefix/etc",      "$gst_prefix/etc/init.d",      "../init.d"],
  111.      "debian-4.0"     => ["$gst_prefix/etc",      "$gst_prefix/etc/init.d",      "../init.d"],
  112.      "debian-5.0"     => ["$gst_prefix/etc",      "$gst_prefix/etc/init.d",      "../init.d"],
  113.      "debian-testing"     => ["$gst_prefix/etc",      "$gst_prefix/etc/init.d",      "../init.d"],
  114.  
  115.      "ubuntu-7.04"    => ["$gst_prefix/etc",      "$gst_prefix/etc/init.d",      "../init.d"],
  116.      "suse-9.0"       => ["$gst_prefix/etc/init.d", "$gst_prefix/etc/init.d",    "../"],
  117.      "pld-1.0"        => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  118.      "vine-3.0"       => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  119.      "ark"            => ["$gst_prefix/etc/rc.d", "$gst_prefix/etc/rc.d/init.d", "../init.d"],
  120.      "solaris-2.11"   => ["$gst_prefix/etc",      "$gst_prefix/etc/init.d",      "../init.d"],
  121.      );
  122.   my $res;
  123.  
  124.   $res = $dist_map{$Utils::Backend::tool{"platform"}};
  125.   &Utils::Report::do_report ("service_sysv_unsupported", $Utils::Backend::tool{"platform"}) if ($res eq undef);
  126.   return @$res;
  127. }
  128.  
  129. # we are going to extract the name of the script
  130. sub get_sysv_service_name
  131. {
  132.     my ($service) = @_;
  133.     
  134.     $service =~ s/$initd_path\///;
  135.   
  136.     return $service;
  137. }
  138.  
  139. # This function gets the state of the service along the runlevels,
  140. # it also returns the average priority
  141. sub get_sysv_runlevels_status
  142. {
  143.     my ($service) = @_;
  144.     my ($link);
  145.     my ($runlevel, $action, $priority);
  146.     my (@arr, @ret);
  147.     
  148.     foreach $link (<$rcd_path/rc[0-6].d/[SK][0-9][0-9]$service>)
  149.     {
  150.         $link =~ s/$rcd_path\///;
  151.         $link =~ /rc([0-6])\.d\/([SK])([0-9][0-9]).*/;
  152.         ($runlevel,$action,$priority)=($1,$2,$3);
  153.  
  154.     if ($action eq "S")
  155.         {
  156.       push @arr, [ $runlevel, $SERVICE_START, $priority ];
  157.     }
  158.         elsif ($action eq "K")
  159.         {
  160.       push @arr, [ $runlevel, $SERVICE_STOP, $priority ];
  161.         }
  162.     }
  163.     
  164.     return \@arr;
  165. }
  166.  
  167. # We are going to extract the information of the service
  168. sub get_sysv_service_info
  169. {
  170.     my ($service) = @_;
  171.     my ($script, @actions, @runlevels, $role);
  172.  
  173.     # Return if it's a directory
  174.     return if (-d $service);
  175.     
  176.     # We have to check if the service is executable    
  177.     return unless (-x $service);
  178.  
  179.     $script = &get_sysv_service_name ($service);
  180.     $runlevels = &get_sysv_runlevels_status($script);
  181.  
  182.   return ($script, $runlevels);
  183. }
  184.  
  185. # This function gets an ordered array of the available services from a SysV system
  186. sub get_sysv_services
  187. {
  188.     my ($service);
  189.     my (@arr);
  190.  
  191.     ($rcd_path, $initd_path) = &get_sysv_paths ();
  192.   return undef unless ($rcd_path && $initd_path);
  193.  
  194.     foreach $service (<$initd_path/*>)
  195.     {
  196.         my (@info);
  197.  
  198.         @info = &get_sysv_service_info ($service);
  199.     push @arr, \@info  if (scalar (@info));
  200.     }
  201.  
  202.     return \@arr;
  203. }
  204.  
  205. # These are the functions for storing the service settings in SysV
  206. sub remove_sysv_link
  207. {
  208.   my ($rcd_path, $runlevel, $script) = @_;
  209.     
  210.   foreach $link (<$rcd_path/rc$runlevel.d/[SK][0-9][0-9]$script>)
  211.   {
  212.     &Utils::Report::enter ();
  213.     &Utils::Report::do_report ("service_sysv_remove_link", "$link");
  214.     unlink ($link);
  215.     &Utils::Report::leave ();
  216.   }
  217. }
  218.  
  219. sub add_sysv_link
  220. {
  221.   my ($rcd_path, $relative_path, $runlevel, $action, $priority, $service) = @_;
  222.   my ($prio) = sprintf ("%0.2d",$priority);
  223.  
  224.   symlink ("$relative_path/$service", "$rcd_path/rc$runlevel.d/$action$prio$service");
  225.  
  226.   &Utils::Report::enter ();
  227.   &Utils::Report::do_report ("service_sysv_add_link", "$rcd_path/rc$runlevel.d/$action$prio$service");
  228.   &Utils::Report::leave ();
  229. }
  230.  
  231. sub run_sysv_initd_script
  232. {
  233.   my ($service, $arg) = @_;
  234.   my ($rc_path, $initd_path);
  235.   my $str;
  236.  
  237.   &Utils::Report::enter ();
  238.   
  239.   ($rcd_path, $initd_path) = &get_sysv_paths ();
  240.   return -1 unless ($rcd_path && $initd_path);
  241.  
  242.   if (-f "$initd_path/$service")
  243.   {
  244.     if (&Utils::File::run ("$initd_path/$service $arg") == 0)
  245.     {
  246.       &Utils::Report::do_report ("service_sysv_op_success", $service, $arg);
  247.       &Utils::Report::leave ();
  248.       return 0;
  249.     }
  250.   }
  251.   
  252.   &Utils::Report::do_report ("service_sysv_op_failed", $service, $arg);
  253.   &Utils::Report::leave ();
  254.   return -1;
  255. }
  256.  
  257. sub set_sysv_service
  258. {
  259.   my ($service) = @_;
  260.   my ($script, $priority, $runlevels, $default_runlevel);
  261.   my ($runlevel, $action, %configured_runlevels);
  262.  
  263.   ($rcd_path, $initd_path, $relative_path) = &get_sysv_paths ();
  264.   return unless ($rcd_path && $initd_path && $relative_path);
  265.  
  266.   $script = $$service[0];
  267.   $runlevels = $$service[1];
  268.   $default_runlevel = &get_sysv_default_runlevel ();
  269.  
  270.   foreach $r (@$runlevels)
  271.   {
  272.     $runlevel = $$r[0];
  273.     $action   = ($$r[1] == $SERVICE_START) ? "S" : "K";
  274.     $priority = sprintf ("%0.2d", $$r[2]);
  275.  
  276.     $configured_runlevels{$runlevel} = 1;
  277.  
  278.     if (!-f "$rcd_path/rc$runlevel.d/$action$priority$script")
  279.     {
  280.       &remove_sysv_link ($rcd_path, $runlevel, $script);
  281.       &add_sysv_link ($rcd_path, $relative_path, $runlevel, $action, $priority, $script);
  282.  
  283.       if ($runlevel eq $default_runlevel)
  284.       {
  285.         &run_sysv_initd_script ($script, ($$r[1] == $SERVICE_START) ? "start" : "stop");
  286.       }
  287.     }
  288.   }
  289.  
  290.   # remove unneeded links
  291.   foreach $link (<$rcd_path/rc[0-6].d/[SK][0-9][0-9]$script>)
  292.     {
  293.     $link =~ /rc([0-6])\.d/;
  294.     $runlevel = $1;
  295.  
  296.     if (!exists $configured_runlevels{$runlevel})
  297.     {
  298.       &remove_sysv_link ($rcd_path, $runlevel, $script);
  299.  
  300.       if ($runlevel eq $default_runlevel)
  301.       {
  302.         &run_sysv_initd_script ($script, "stop");
  303.       }
  304.     }
  305.   }
  306. }
  307.  
  308. sub set_sysv_services
  309. {
  310.     my ($services) = @_;
  311.  
  312.     foreach $i (@$services)
  313.     {
  314.         &set_sysv_service($i);
  315.     }
  316. }
  317.  
  318. # This functions get an ordered array of the available services from a file-rc system
  319. sub get_filerc_runlevels_status
  320. {
  321.   my ($start_service, $stop_service, $priority) = @_;
  322.   my (@arr);
  323.  
  324.   # we start with the runlevels in which the service starts
  325.   if ($start_service !~ /-/) {
  326.     my (@runlevels);
  327.  
  328.     @runlevels = split /,/, $start_service;
  329.  
  330.     foreach $runlevel (@runlevels)
  331.     {
  332.       push @arr, [ $runlevel, $SERVICE_START, $priority ];
  333.     }
  334.   }
  335.  
  336.   # now let's go with the runlevels in which the service stops
  337.   if ($stop_service !~ /-/) {
  338.     my (@runlevels);
  339.  
  340.     @runlevels = split /,/, $stop_service;
  341.  
  342.     foreach $runlevel (@runlevels)
  343.     {
  344.       push @arr, [ $runlevel, $SERVICE_STOP, $priority ];
  345.     }
  346.   }
  347.  
  348.   return \@arr;
  349. }
  350.  
  351. sub get_filerc_service_info
  352. {
  353.   my ($line, %ret) = @_;
  354.   my (@runlevels, $role);
  355.  
  356.   if ($line =~ /^([0-9][0-9])[\t ]+([0-9\-S,]+)[\t ]+([0-9\-S,]+)[\t ]+\/etc\/init\.d\/(.*)/)
  357.   {
  358.     $priority = $1;
  359.     $stop_service = $2;
  360.     $start_service = $3;
  361.     $script = $4;
  362.  
  363.     $runlevels = &get_filerc_runlevels_status ($start_service, $stop_service, $priority);
  364.  
  365.     return ($script, $runlevels);
  366.   }
  367.  
  368.   return;
  369. }
  370.  
  371. sub get_filerc_services
  372. {
  373.     my ($script);
  374.   my ($script, @arr, %hash);
  375.  
  376.   open FILE, "$gst_prefix/etc/runlevel.conf" or return undef;
  377.   while ($line = <FILE>)
  378.   {
  379.     next if ($line =~ /^\#.*/);
  380.  
  381.     my (@info);
  382.     my ($start_service, $stop_service);
  383.  
  384.     @info = &get_filerc_service_info ($line);
  385.     next if (!scalar (@info));
  386.  
  387.     $script = $info[0];
  388.  
  389.     if (!$hash{$script})
  390.     {
  391.       $hash{$script} = \@info;
  392.     }
  393.     else
  394.     {
  395.       # We need to mix the runlevels
  396.       foreach $runlevel (@{$info[2]})
  397.       {
  398.         push @{$hash{$script}[2]}, $runlevel;
  399.       }
  400.     }
  401.   }
  402.  
  403.   foreach $key (keys %hash)
  404.   {
  405.     push @arr, $hash{$key};
  406.   }
  407.  
  408.   return \@arr;
  409. }
  410.  
  411. # These are the functions for storing the service settings in file-rc
  412. sub concat_filerc_runlevels
  413. {
  414.   my (@runlevels) = @_;
  415.  
  416.   $str = join (",", sort (@runlevels));
  417.   return ($str) ? $str : "-";
  418. }
  419.  
  420. sub set_filerc_service
  421. {
  422.   my ($buff, $initd_path, $service) = @_;
  423.   my (%hash, $priority, $line, $str);
  424.   my ($script, $default_runlevel, %configured_runlevels);
  425.  
  426.   $script = $$service[0];
  427.   $runlevels = $$service[1];
  428.   $default_runlevel = &get_sysv_default_runlevel ();
  429.  
  430.   foreach $i (@$runlevels)
  431.   {
  432.     $priority = 0 + $$i[2];
  433.     $priority = 50 if ($priority == 0); #very rough guess
  434.     $configured_runlevels {$$i[0]} = 1;
  435.  
  436.     if ($$i[1] == $SERVICE_START)
  437.     {
  438.       $hash{$priority}{$SERVICE_START} = [] if (!$hash{$priority}{$SERVICE_START});
  439.       push @{$hash{$priority}{$SERVICE_START}}, $$i[0];
  440.     }
  441.     else
  442.     {
  443.       $hash{$priority}{$SERVICE_STOP} = [] if (!$hash{$priority}{$SERVICE_STOP});
  444.       push @{$hash{$priority}{$SERVICE_STOP}}, $$i[0];
  445.     }
  446.  
  447.     if ($$i[0] eq $default_runlevel)
  448.     {
  449.       &run_sysv_initd_script ($script, ($$i[1] == $SERVICE_START) ? "start" : "stop");
  450.     }
  451.   }
  452.  
  453.   foreach $priority (keys %hash)
  454.   {
  455.     $line  = sprintf ("%0.2d", $priority) . "\t";
  456.     $line .= &concat_filerc_runlevels (@{$hash{$priority}{$SERVICE_STOP}}) . "\t";
  457.     $line .= &concat_filerc_runlevels (@{$hash{$priority}{$SERVICE_START}}) . "\t";
  458.     $line .= $initd_path . "/" . $script . "\n";
  459.  
  460.     push @$buff, $line;
  461.   }
  462.  
  463.   # stop the service if it's not configured
  464.   if (!$configured_runlevels {$default_runlevel})
  465.   {
  466.     &run_sysv_initd_script ($script, "stop");
  467.   }
  468. }
  469.  
  470. sub set_filerc_services
  471. {
  472.   my ($services) = @_;
  473.   my ($buff, $lineno, $line, $file);
  474.   my ($rcd_path, $initd_path, $relative_path) = &get_sysv_paths ();
  475.   return unless ($rcd_path && $initd_path && $relative_path);
  476.  
  477.   $file = "/etc/runlevel.conf";
  478.  
  479.   $buff = &Utils::File::load_buffer ($file);
  480.   &Utils::File::join_buffer_lines ($buff);
  481.  
  482.   $lineno = 0;
  483.  
  484.   # We prepare the file for storing the configuration, save the initial comments
  485.   # and delete the rest
  486.   while ($$buff[$lineno] =~ /^#.*/)
  487.   {
  488.     $lineno++;
  489.   }
  490.  
  491.   for ($i = $lineno; $i < scalar (@$buff); $i++)
  492.   {
  493.     $$buff[$i] =~ /.*\/etc\/init\.d\/(.*)/;
  494.  
  495.     # we need to keep the forbidden services and the services that only start in rcS.d
  496.     # FIXME: need to remove this call to is_forbidden
  497.     if (!&Init::ServicesList::is_forbidden ($1))
  498.     {
  499.       delete $$buff[$i];
  500.     }
  501.   }
  502.  
  503.   # Now we append the services
  504.   foreach $service (@$services)
  505.   {
  506.     &set_filerc_service ($buff, $initd_path, $service);
  507.   }
  508.  
  509.   @$buff = sort @$buff;
  510.  
  511.   push @$buff, "\n";
  512.   &Utils::File::clean_buffer ($buff);
  513.   &Utils::File::save_buffer ($buff, $file);
  514. }
  515.  
  516. # this functions get a list of the services that run on a bsd init
  517. sub get_bsd_scripts_list
  518. {
  519.   my ($files) = [ "rc.M", "rc.inet2", "rc.4" ];
  520.   my ($file, $i, %scripts);
  521.   my ($service, $name);
  522.  
  523.   foreach $i (@$files)
  524.   {
  525.     $file = "/etc/rc.d/" . $i;
  526.     $fd = &Utils::File::open_read_from_names ($file);
  527.  
  528.     if (!$fd) {
  529.       &Utils::Report::do_report ("rc_file_read_failed", $file);
  530.       next;
  531.     }
  532.  
  533.     while (<$fd>)
  534.     {
  535.       $line = $_;
  536.  
  537.       if ($line =~ /^if[ \t]+\[[ \t]+\-x[ \t]([0-9a-zA-Z\/\.\-_]+) .*\]/)
  538.       {
  539.         $service = $1;
  540.         $name = $service;
  541.         $name =~ s/^.*\///;
  542.         $name =~ s/^rc\.//;
  543.  
  544.         $scripts{$name} = $service;
  545.       }
  546.     }
  547.  
  548.     &Utils::File::close_file ($fd);
  549.   }
  550.  
  551.   return \%scripts;
  552. }
  553.  
  554. sub get_bsd_service_status
  555. {
  556.   my ($service) = @_;
  557.   return (-x $service) ? $SERVICE_START : $SERVICE_STOP;
  558. }
  559.  
  560. sub get_bsd_service_info
  561. {
  562.   my ($service, $name) = @_;
  563.   my (@runlevels, $status);
  564.  
  565.   return if (! Utils::File::exists ($service));
  566.  
  567.   $status = &get_bsd_service_status ($service);
  568.   push @runlevels, [ "default", $status, 0 ];
  569.  
  570.   return ($name, \@runlevels);
  571. }
  572.  
  573. sub get_bsd_services
  574. {
  575.   my (@arr, %scripts, $name);
  576.  
  577.   $scripts = &get_bsd_scripts_list ();
  578.  
  579.   foreach $name (keys %$scripts)
  580.   {
  581.     my (@info);
  582.  
  583.     @info = &get_bsd_service_info ($$scripts{$name}, $name);
  584.     push @arr, \@info if (scalar (@info));
  585.   }
  586.  
  587.   return \@arr;
  588. }
  589.  
  590. sub run_bsd_script
  591. {
  592.   my ($service, $arg) = @_;
  593.   my ($chmod) = 0;
  594.  
  595.   return if (!&Utils::File::exists ($service));
  596.  
  597.   # if it's not executable then chmod it
  598.   if (! -x $service)
  599.   {
  600.     $chmod = 1;
  601.     &Utils::File::run ("chmod ugo+x $service");
  602.   }
  603.  
  604.   &Utils::File::run ("$service $arg", 1);
  605.  
  606.   # return it to it's normal state
  607.   if ($chmod)
  608.   {
  609.     &Utils::File::run ("chmod ugo-x $service");
  610.   }
  611. }
  612.  
  613. # This function stores the configuration in a bsd init
  614. sub set_bsd_services
  615. {
  616.   my ($services) = @_;
  617.   my ($script, $runlevels, %scripts);
  618.   my ($status);
  619.  
  620.   $scripts = &get_bsd_scripts_list ();
  621.  
  622.   foreach $service (@$services)
  623.   {
  624.     $script = $$scripts{$$service[0]};
  625.     $runlevels = $$service[1];
  626.     $runlevel  = $$runlevels[0];
  627.  
  628.     next if ($script eq undef);
  629.  
  630.     $status = $$runlevel[1];
  631.     $status = $SERVICE_STOP if ($status eq undef);
  632.  
  633.     next if ($status == &get_bsd_service_status ($script));
  634.  
  635.     if ($status == $SERVICE_START)
  636.     {
  637.       &Utils::File::run ("chmod ugo+x $script");
  638.       &run_bsd_script ($script, "start");
  639.     }
  640.     else
  641.     {
  642.       &run_bsd_script ($script, "stop");
  643.       &Utils::File::run ("chmod ugo-x $script");
  644.     }
  645.   }
  646. }
  647.  
  648. # these functions get a list of the services that run on a gentoo init
  649. sub get_gentoo_service_status
  650. {
  651.   my ($script, $runlevel) = @_;
  652.   my ($services) = &get_gentoo_services_for_runlevel ($runlevel);
  653.  
  654.   return ($$services {$script});
  655. }
  656.  
  657. sub get_gentoo_runlevels
  658. {
  659.   my($raw_output) = Utils::File::run_backtick("rc-status --nocolor -l");
  660.   my(@runlevels);
  661.  
  662.   return undef if (!$raw_output);
  663.   @runlevels = split(/\n/,$raw_output);
  664.  
  665.   return \@runlevels;
  666. }
  667.  
  668. sub get_gentoo_services_for_runlevel
  669. {
  670.   my($runlevel) = @_;
  671.   my($raw_output) = Utils::File::run_backtick("rc-status -nocolor $runlevel");
  672.   my(@raw_lines) = split(/\n/,$raw_output);
  673.   my($line, $service);
  674.   my(%services);
  675.  
  676.   foreach $line (@raw_lines)
  677.   {
  678.     if ($line !~ /^Runlevel/)
  679.     {
  680.       $service = (split(" ",$line))[0];
  681.       $services{$service} = 1;
  682.       }
  683.   }
  684.  
  685.   return \%services
  686. }
  687.  
  688. sub get_gentoo_runlevels_services
  689. {
  690.   my (%runlevels_services, $runlevels);
  691.  
  692.   $runlevels = &get_gentoo_runlevels ();
  693.   return undef if (!$runlevels);
  694.  
  695.   foreach $runlevel (@$runlevels)
  696.   {
  697.     $runlevels_services{$runlevel} = &get_gentoo_services_for_runlevel ($runlevel);
  698.   }
  699.  
  700.   return \%runlevels_services;
  701. }
  702.  
  703. sub get_gentoo_services_list
  704. {
  705.   my ($service, @services);
  706.  
  707.   foreach $service (<$gst_prefix/etc/init.d/*>)
  708.   {
  709.     if (-x $service)
  710.     {
  711.       $service =~ s/.*\///;
  712.       push @services, $service;
  713.     }
  714.   }
  715.  
  716.   return \@services;
  717. }
  718.  
  719. sub gentoo_service_exists
  720. {
  721.   my($service) = @_;
  722.   my($services) = &get_gentoo_services_list();
  723.  
  724.   foreach $i (@$services)
  725.   {
  726.     return 1 if ($i =~ /$service/);
  727.   }
  728.  
  729.   return 0;
  730. }
  731.  
  732. sub get_gentoo_runlevels_status
  733. {
  734.   my ($service, $runlevels_services) = @_;
  735.   my (@arr, $services_in_runlevel);
  736.  
  737.   foreach $runlevel (keys %$runlevels_services)
  738.   {
  739.     $services_in_runlevel = $$runlevels_services {$runlevel};
  740.  
  741.     if ($$services_in_runlevel{$service})
  742.     {
  743.       push @arr, [ $runlevel, $SERVICE_START, 0 ];
  744.     }
  745.     else
  746.     {
  747.       push @arr, [ $runlevel, $SERVICE_STOP, 0 ];
  748.     }
  749.   }
  750.  
  751.   return \@arr;
  752. }
  753.  
  754. sub get_gentoo_service_info
  755. {
  756.   my ($service, $runlevels_services) = @_;
  757.   my (@runlevels_info);
  758.  
  759.   $runlevels_info = &get_gentoo_runlevels_status ($service, $runlevels_services);
  760.  
  761.   return ($service, $runlevels_info);
  762. }
  763.  
  764. sub get_gentoo_services
  765. {
  766.   my ($service, @arr);
  767.   my ($service_list) = &get_gentoo_services_list ();
  768.   my ($runlevels_services) = &get_gentoo_runlevels_services ();
  769.  
  770.   foreach $service (@$service_list)
  771.   {
  772.     my (@info);
  773.  
  774.     @info = &get_gentoo_service_info ($service, $runlevels_services);
  775.     push @arr, \@info if scalar (@info);
  776.   }
  777.  
  778.   return \@arr;
  779. }
  780.  
  781. #FIXME: almost equal to the sysv equivalent
  782. sub run_gentoo_script
  783. {
  784.   my ($service, $arg) = @_;
  785.  
  786.   &Utils::Report::enter ();
  787.  
  788.   if (&gentoo_service_exists ($service))
  789.   {
  790.     if (!&Utils::File::run ("/etc/init.d/$service $arg"))
  791.     {
  792.       &Utils::Report::do_report ("service_sysv_op_success", $service, $arg);
  793.       &Utils::Report::leave ();
  794.         return 0;
  795.       }
  796.   }
  797.  
  798.   &Utils::Report::do_report ("service_sysv_op_failed", $service, $arg);
  799.   &Utils::Report::leave ();
  800.   return -1;
  801. }
  802.  
  803. sub set_gentoo_service_status
  804. {
  805.   my ($script, $rl, $status, $runlevels_services) = @_;
  806.   my ($services_in_runlevel, $old_status);
  807.  
  808.   $services_in_runlevel = $$runlevels_services {$rl};
  809.   $old_status = ($$services_in_runlevel{$script}) ?
  810.       $SERVICE_START : $SERVICE_STOP;
  811.  
  812.   return if ($status == $old_status);
  813.  
  814.   if ($action == $SERVICE_START)
  815.   {
  816.     &Utils::File::run ("rc-update add $script $rl");
  817.     &run_gentoo_script ($script, "start");
  818.   }
  819.   else
  820.   {
  821.     &run_gentoo_script ($script, "stop");
  822.     &Utils::File::run ("rc-update del $script $rl");
  823.   }
  824. }
  825.  
  826. # This function stores the configuration in gentoo init
  827. sub set_gentoo_services
  828. {
  829.   my ($services) = @_;
  830.   my ($action, $rl, $script, $arr);
  831.   my ($runlevels_services) = &get_gentoo_runlevels_services ();
  832.  
  833.   return if (!$runlevels_services);
  834.  
  835.   foreach $service (@$services)
  836.   {
  837.     $script = $$service[0];
  838.     $arr = $$service[1];
  839.  
  840.     foreach $i (@$arr)
  841.     {
  842.       $action = $$i[1];
  843.       $rl = $$i[0];
  844.       &set_gentoo_service_status ($script, $rl, $action,
  845.                                   $runlevels_services);
  846.     }
  847.   }
  848. }
  849.  
  850. # rcNG functions, mostly for FreeBSD
  851. sub get_rcng_status_by_service
  852. {
  853.   my ($service) = @_;
  854.   my ($fd, $line, $active);
  855.  
  856.   # This is the only difference between rcNG and archlinux
  857.   if ($Utils::Backend::tool{"platform"} eq "archlinux")
  858.   {
  859.     return &Utils::File::exists ("/var/run/daemons/$service");
  860.   }
  861.   else
  862.   {
  863.     $fd = &Utils::File::run_pipe_read ("/etc/rc.d/$service rcvar");
  864.  
  865.     while (<$fd>)
  866.     {
  867.       $line = $_;
  868.  
  869.       if ($line =~ /^\$.*=YES$/)
  870.       {
  871.         $active = 1;
  872.         last;
  873.       }
  874.     }
  875.  
  876.     &Utils::File::close_file ($fd);
  877.     return $active;
  878.   }
  879. }
  880.  
  881. sub get_rcng_service_info
  882. {
  883.   my ($script) = @_;
  884.   my (@runlevels);
  885.  
  886.   if (get_rcng_status_by_service ($script))
  887.   {
  888.     push @runlevels, [ "default", $SERVICE_START, 0 ];
  889.   }
  890.   else
  891.   {
  892.     push @runlevels, [ "default", $SERVICE_STOP, 0 ];
  893.   }
  894.  
  895.   return ($script, \@runlevels);
  896. }
  897.  
  898. sub get_rcng_services
  899. {
  900.   my ($service);
  901.   my (@arr);
  902.  
  903.   foreach $service (<$gst_prefix/etc/rc.d/*>)
  904.   {
  905.     my (@info);
  906.  
  907.     $service =~ s/.*\///;
  908.     @info = &get_rcng_service_info ($service);
  909.     push @arr, \@info if (scalar (@info));
  910.   }
  911.  
  912.   return \@arr;
  913. }
  914.  
  915. sub run_rcng_script
  916. {
  917.   my ($service, $arg) = @_;
  918.  
  919.   &Utils::Report::enter ();
  920.  
  921.   if (!&Utils::File::run ("/etc/rc.d/$service $arg"))
  922.   {
  923.     &Utils::Report::do_report ("service_sysv_op_success", $service, $arg);
  924.     &Utils::Report::leave ();
  925.     return 0;
  926.   }
  927.  
  928.   &Utils::Report::do_report ("service_sysv_op_failed", $service, $arg);
  929.   &Utils::Report::leave ();
  930.   return -1;
  931. }
  932.  
  933. # These functions store the configuration of a rcng init
  934. sub set_rcng_service_status
  935. {
  936.   my ($service, $action) = @_;
  937.   my ($fd, $key, $res);
  938.   my ($default_rcconf) = "/etc/defaults/rc.conf";
  939.   my ($rcconf) = "/etc/rc.conf";
  940.  
  941.   if (&Utils::File::exists ("/etc/rc.d/$service"))
  942.   {
  943.     $fd = &Utils::File::run_pipe_read ("/etc/rc.d/$service rcvar");
  944.  
  945.     while (<$fd>)
  946.     {
  947.       if (/^\$(.*)=.*$/)
  948.       {
  949.         # to avoid cluttering rc.conf with duplicated data,
  950.         # we first look in the defaults/rc.conf for the key
  951.         $key = $1;
  952.         $res = &Utils::Parse::get_sh_bool ($default_rcconf, $key);
  953.  
  954.         if ($res == $action)
  955.         {
  956.           &Utils::Replace::set_sh ($rcconf, $key);
  957.         }
  958.         else
  959.         {
  960.           &Utils::Replace::set_sh_bool ($rcconf, $key, "YES", "NO", $action);
  961.         }
  962.  
  963.         &run_rcng_script ($service, ($action) ? "forcestart" : "forcestop");
  964.       }
  965.     }
  966.  
  967.     &Utils::File::close_file ($fd);
  968.   }
  969.   elsif (&Utils::File::exists ("/usr/local/etc/rc.d/$service.sh"))
  970.   {
  971.     if ($action)
  972.     {
  973.       &Utils::File::copy_file ("/usr/local/etc/rc.d/$service.sh.sample",
  974.                               "/usr/local/etc/rc.d/$service.sh");
  975.       &run_rcng_script ($service, "forcestart");
  976.     }
  977.     else
  978.     {
  979.       &run_rcng_script ($service, "forcestop");
  980.       Utils::File::remove ("/usr/local/etc/rc.d/$service.sh");
  981.     }
  982.   }
  983. }
  984.  
  985. sub set_archlinux_service_status
  986. {
  987.   my ($script, $active) = @_;
  988.   my $rcconf = '/etc/rc.conf';
  989.   my ($daemons);
  990.  
  991.   $daemons = &Utils::Parse::get_sh ($rcconf, "DAEMONS");
  992.   $daemons =~ s/[\(\)]//g;
  993.  
  994.   # escape these chars
  995.   $script =~ s/([\\\.\^\$\*\+\?\{\}\[\]\(\)\|])/\\\1/g;
  996.   $notscript = "\!" . $script;
  997.  
  998.   if (($daemons =~ m/$notscript/) && $active)
  999.   {
  1000.     # It was disabled, enable it
  1001.     $daemons =~ s/$notscript/$script/g;
  1002.   }
  1003.   elsif (($daemons =~ m/$script/) && !$active)
  1004.   {
  1005.     # It was enabled, disable it
  1006.     $daemons =~ s/$script/$notscript/g;
  1007.   }
  1008.   elsif (($daemons !~ m/$script/) && $active)
  1009.   {
  1010.     $daemons .= " ".$script;
  1011.   }
  1012.  
  1013.   $daemons = "(" . $daemons . ")";
  1014.   &Utils::Replace::set_sh ($rcconf, "DAEMONS", $daemons, 1);
  1015.   &run_rcng_script ($service, ($active) ? "start" : "stop");
  1016. }
  1017.  
  1018. sub set_rcng_services
  1019. {
  1020.   my ($services) = @_;
  1021.   my ($action, $runlevels, $script, $func);
  1022.  
  1023.   # archlinux stores services differently
  1024.   if ($Utils::Backend::tool{"platform"} eq "archlinux")
  1025.   {
  1026.     $func = \&set_archlinux_service_status;
  1027.   }
  1028.   else
  1029.   {
  1030.     $func = \&set_rcng_service_status;
  1031.   }
  1032.  
  1033.   foreach $service (@$services)
  1034.   {
  1035.     $script    = $$service[0];
  1036.     $runlevels = $$service[1];
  1037.     $runlevel  = $$runlevels[0];
  1038.     $action    = ($$runlevel[1] == $SERVICE_START)? 1 : 0;
  1039.  
  1040.     &$func ($script, $action);
  1041.   }
  1042. }
  1043.  
  1044. # SuSE functions, quite similar to SysV, but not equal...
  1045. sub get_suse_service_info ($service)
  1046. {
  1047.   my ($service) = @_;
  1048.   my (@runlevels, $link, $runlevel);
  1049.  
  1050.   foreach $link (<$rcd_path/rc[0-9S].d/S[0-9][0-9]$service>)
  1051.   {
  1052.     $link =~ s/$rcd_path\///;
  1053.     $link =~ /rc([0-6])\.d\/S[0-9][0-9].*/;
  1054.     $runlevel = $1;
  1055.  
  1056.     push @runlevels, [ $runlevel, $SERVICE_START, 0 ];
  1057.   }
  1058.  
  1059.   foreach $link (<$rcd_path/boot.d/S[0-9][0-9]$service>)
  1060.   {
  1061.     push @runlevels, [ "B", $SERVICE_START, 0 ];
  1062.   }
  1063.  
  1064.   return ($service, $runlevels);
  1065. }
  1066.  
  1067. sub get_suse_services
  1068. {
  1069.   my ($service, @arr);
  1070.  
  1071.   ($rcd_path, $initd_path) = &get_sysv_paths ();
  1072.   return undef unless ($rcd_path && $initd_path);
  1073.  
  1074.   foreach $service (<$gst_prefix/etc/init.d/*>)
  1075.   {
  1076.     my (@info);
  1077.  
  1078.     next if (-d $service || ! -x $service);
  1079.  
  1080.     $service =~ s/.*\///;
  1081.     @info = &get_suse_service_info ($service);
  1082.     push @arr, \@info  if (scalar (@info));
  1083.   }
  1084.  
  1085.   return \@arr;
  1086. }
  1087.  
  1088. # This function stores the configuration in suse init
  1089. sub set_suse_services
  1090. {
  1091.   my ($services) = @_;
  1092.   my ($action, $runlevels, $script, $rllist);
  1093.   my (%configured_runlevels, $default_runlevel);
  1094.  
  1095.   $default_runlevel = &get_sysv_default_runlevel ();
  1096.  
  1097.   foreach $service (@$services)
  1098.   {
  1099.     $script = $$service[0];
  1100.     $runlevels = $$service[1];
  1101.     $rllist = "";
  1102.     %configured_runlevels = {};
  1103.  
  1104.     &Utils::File::run ("insserv -r $script");
  1105.  
  1106.     foreach $rl (@$runlevels)
  1107.     {
  1108.       $configured_runlevels{$$rl[0]} = 1;
  1109.  
  1110.       if ($$rl[1] == $SERVICE_START)
  1111.       {
  1112.         $rllist .= $$rl[0] . ",";
  1113.       }
  1114.  
  1115.       &run_sysv_initd_script ($script, ($$rl[1] == $SERVICE_START) ? "start" : "stop");
  1116.     }
  1117.  
  1118.     if ($rllist ne "")
  1119.     {
  1120.       $rllist =~ s/,$//;
  1121.  
  1122.       &Utils::File::run ("insserv $script,start=$rllist");
  1123.     }
  1124.  
  1125.     if (!$configured_runlevels{$default_runlevel})
  1126.     {
  1127.       &run_sysv_initd_script ($script, $$rl[1]);
  1128.     }
  1129.   }
  1130. }
  1131.  
  1132. # functions to get/set services info in smf
  1133. sub smf_service_exists
  1134. {
  1135.   my($service) = @_;
  1136.   my($services) = &get_smf_services_list ();
  1137.  
  1138.   foreach $i (@$services)
  1139.   {
  1140.     return 1 if ($i =~ /$service/);
  1141.   }
  1142.  
  1143.   return 0;
  1144. }
  1145.  
  1146. sub run_smf_svcadm
  1147. {
  1148.   my ($service, $arg) = @_;
  1149.   my ($option);
  1150.  
  1151.   my %op =
  1152.     ("stop" => "disable",
  1153.      "start" => "enable"
  1154.     );
  1155.  
  1156.   if (&smf_service_exists ($service))
  1157.   {
  1158.     if (!&Utils::File::run ("svcadm $op{$arg} $service"))
  1159.     {
  1160.       &Utils::Report::do_report ("service_sysv_op_success", $service, $arg);
  1161.       &Utils::Report::leave ();
  1162.       return 0;
  1163.     }
  1164.   }
  1165.  
  1166.   &Utils::Report::do_report ("service_sysv_op_failed", $service, $arg);
  1167.   &Utils::Report::leave ();
  1168.   return -1;
  1169. }
  1170.  
  1171. sub get_smf_runlevel_status_by_service
  1172. {
  1173.   my ($service, $status) = @_;
  1174.   my (@arr);
  1175.  
  1176.   if ($status)
  1177.   {
  1178.     push @arr, [ "default", $SERVICE_START, 0 ];
  1179.   }
  1180.   else
  1181.   {
  1182.     push @arr, [ "default", $SERVICE_STOP, 0 ];
  1183.   }
  1184.  
  1185.   return \@arr;
  1186. }
  1187.  
  1188. sub get_smf_service_info
  1189. {
  1190.   my ($service) = @_;
  1191.   my ($fd, @runlevels);
  1192.   my $status = 0;
  1193.  
  1194.   $fd = &Utils::File::run_pipe_read ("svcs -l $service");
  1195.  
  1196.   while (<$fd>)
  1197.   {
  1198.     $status = 1 if (/^state.*online/);
  1199.   }
  1200.  
  1201.   &Utils::File::close_file ($fd);
  1202.  
  1203.   $runlevels = &get_smf_runlevel_status_by_service ($service, $status);
  1204.   $service =~ m/.*\/(.*)$/;
  1205.  
  1206.   return ($service, $runlevels);
  1207. }
  1208.  
  1209. sub get_smf_services_list
  1210. {
  1211.   my ($fd, @list);
  1212.  
  1213.   $fd = &Utils::File::run_pipe_read ("svcs -H -a");
  1214.  
  1215.   while (<$fd>)
  1216.   {
  1217.     next if (/svc:\/milestone/);
  1218.  
  1219.     if (/^.*\s*.*\s*svc:\/(.*):.*/)
  1220.     {
  1221.       push @list, $1;
  1222.     }
  1223.   }
  1224.  
  1225.   &Utils::File::close_file ($fd);
  1226.   return \@list;
  1227. }
  1228.  
  1229. sub get_smf_services
  1230. {
  1231.   my ($service, @arr);
  1232.   my ($service_list) = &get_smf_services_list ();
  1233.  
  1234.   foreach $service (@$service_list)
  1235.   {
  1236.     my (@info);
  1237.  
  1238.     @info = &get_smf_service_info ($service);
  1239.     push @arr, \@info if scalar (@info);
  1240.   }
  1241.  
  1242.   return \@arr;
  1243. }
  1244.  
  1245. sub set_smf_service_status
  1246. {
  1247.   my ($service, $rl, $active) = @_;
  1248.   my ($info);
  1249.  
  1250.   $info = &get_smf_service_info ($service);
  1251.  
  1252.   #return if service has not changed
  1253.   return if ($active == @{@$info[0]}[1]);
  1254.  
  1255.   if ($active == $SERVICE_START)
  1256.   {
  1257.     &Utils::File::run ("svcadm enable -s $service");
  1258.   }
  1259.   else
  1260.   {
  1261.     &Utils::File::run ("svcadm disable -s $service");
  1262.   }
  1263. }
  1264.  
  1265. sub set_smf_services
  1266. {
  1267.   my ($services) = @_;
  1268.   my ($action, $rl, $script, $arr);
  1269.  
  1270.   foreach $service (@$services)
  1271.   {
  1272.     $script = $$service[0];
  1273.     $arr = $$service[1];
  1274.  
  1275.     foreach $i (@$arr)
  1276.     {
  1277.       $action = $$i[1];
  1278.       $rl = $$i[0];
  1279.       &set_smf_service_status ($script, $rl, $action);
  1280.     }
  1281.   }
  1282. }
  1283.  
  1284. # generic functions to get the available services
  1285. sub get_init_type
  1286. {
  1287.   my $gst_dist;
  1288.  
  1289.   $gst_dist = $Utils::Backend::tool{"platform"};
  1290.  
  1291.   if (($gst_dist =~ /debian/) && (Utils::File::exists ("/etc/runlevel.conf")))
  1292.   {
  1293.     return "file-rc";
  1294.   }
  1295.   elsif ($gst_dist =~ /slackware/)
  1296.   {
  1297.     return "bsd";
  1298.   }
  1299.   elsif (($gst_dist =~ /freebsd/) || ($gst_dist =~ /archlinux/))
  1300.   {
  1301.     return "rcng";
  1302.   }
  1303.   elsif ($gst_dist =~ /gentoo/)
  1304.   {
  1305.     return "gentoo";
  1306.   }
  1307.   elsif ($gst_dist =~ /suse/)
  1308.   {
  1309.     return "suse";
  1310.   }
  1311.   elsif ($gst_dist =~ /solaris/)
  1312.   {
  1313.     return "smf";
  1314.   }
  1315.   else
  1316.   {
  1317.     return "sysv";
  1318.   }
  1319. }
  1320.  
  1321. sub run_script
  1322. {
  1323.   my ($service, $arg) = @_;
  1324.   my ($proc, $type);
  1325.   my %map =
  1326.     (
  1327.      "sysv"    => \&run_sysv_initd_script,
  1328.      "file-rc" => \&run_sysv_initd_script,
  1329.      "bsd"     => \&run_bsd_script,
  1330.      "gentoo"  => \&run_gentoo_script,
  1331.      "rcng"    => \&run_rcng_script,
  1332.      "suse"    => \&run_sysv_initd_script,
  1333.      "smf"     => \&run_smf_svcadm,
  1334.     );
  1335.  
  1336.   $type = &get_init_type ();
  1337.   $proc = $map {$type};
  1338.   &$proc ($service, $arg);
  1339. }
  1340.  
  1341. sub get
  1342. {
  1343.   $type = &get_init_type ();
  1344.  
  1345.   return &get_sysv_services ()   if ($type eq "sysv");
  1346.   return &get_filerc_services () if ($type eq "file-rc");
  1347.   return &get_bsd_services ()    if ($type eq "bsd");
  1348.   return &get_gentoo_services () if ($type eq "gentoo");
  1349.   return &get_rcng_services ()   if ($type eq "rcng");
  1350.   return &get_suse_services ()   if ($type eq "suse");
  1351.   return &get_smf_services ()    if ($type eq "smf");
  1352.  
  1353.   return undef;
  1354. }
  1355.  
  1356. sub set
  1357. {
  1358.     my ($services) = @_;
  1359.  
  1360.   $type = &get_init_type ();
  1361.  
  1362.   &set_sysv_services   ($services) if ($type eq "sysv");
  1363.   &set_filerc_services ($services) if ($type eq "file-rc");
  1364.   &set_bsd_services    ($services) if ($type eq "bsd");
  1365.   &set_gentoo_services ($services) if ($type eq "gentoo");
  1366.   &set_rcng_services   ($services) if ($type eq "rcng");
  1367.   &set_suse_services   ($services) if ($type eq "suse");
  1368.   &set_smf_services    ($services) if ($type eq "smf");
  1369. }
  1370.  
  1371. 1;
  1372.