diff options
Diffstat (limited to 'perl-install/services.pm')
| -rw-r--r-- | perl-install/services.pm | 270 | 
1 files changed, 180 insertions, 90 deletions
| diff --git a/perl-install/services.pm b/perl-install/services.pm index 6a77844e9..c2230351d 100644 --- a/perl-install/services.pm +++ b/perl-install/services.pm @@ -1,4 +1,4 @@ -package services; # $Id: services.pm 267089 2010-03-28 12:51:44Z tv $ +package services; @@ -13,6 +13,19 @@ use run_program;  use File::Basename; +sub _unit_name { +    my ($service) = @_; +    return $service if $service =~ /\.(service|socket|timer)$/; +    "$service.service"; +} + +#- The name used in the lists returned by services(). For backwards compatibility, +#- use just the base name for .service units. +sub _list_name { +    my ($name, $type) = @_; +    $type eq 'service' ? $name : "$name.$type"; +} +  sub description {      my %services = (  acpid => N_("Listen and dispatch ACPI events from the kernel"),	     @@ -23,6 +36,7 @@ It can also be used for shutting down the machine when the battery is low."),  atd => N_("Runs commands scheduled by the at command at the time specified when  at was run, and runs batch commands when the load average is low enough."),  'avahi-deamon' => N_("Avahi is a ZeroConf daemon which implements an mDNS stack"), +chronyd => N_("An NTP client/server"),  cpufreq => N_("Set CPU frequency settings"),  crond => N_("cron is a standard UNIX program that runs user-specified programs  at periodic scheduled times. vixie cron adds a number of features to the basic @@ -108,8 +122,9 @@ rusersd => N_("The rusers protocol allows users on a network to identify who is  logged in on other responding machines."),  rwhod => N_("The rwho protocol lets remote users get a list of all of the users  logged into a machine running the rwho daemon (similar to finger)."), -saned => N_("SANE (Scanner Access Now Easy) enables to access scanners, video cameras, ..."), +'saned.socket' => N_("SANE (Scanner Access Now Easy) enables to access scanners, video cameras, ..."),  shorewall => N_("Packet filtering firewall"), +shorewall6 => N_("Packet filtering firewall for IPv6"),  smb => N_("The SMB/CIFS protocol enables to share access to files & printers and also integrates with a Windows Server domain"),  sound => N_("Launch the sound system on your machine"),  'speech-dispatcherd' => N_("layer for speech analysis"), @@ -127,14 +142,20 @@ xinetd => N_("Starts other deamons on demand."),      if ($s) {  	$s = translate($s);      } else { -	my $file = find { -e $_ } map { "$::prefix$_/$name" } '/etc/rc.d/init.d', '/etc/init.d', '/etc/xinetd.d'; -	$s = cat_($file); -	$s =~ s/\\\s*\n#\s*//mg; -	$s =  -	  $s =~ /^#\s+(?:Short-)?[dD]escription:\s+(.*?)^(?:[^#]|# {0,2}\S)/sm ? $1 : -	  $s =~ /^#\s*(.*?)^[^#]/sm ? $1 : ''; - -	$s =~ s/#\s*//mg; +	my $file = "$::prefix/usr/lib/systemd/system/" . _unit_name($name); +	if (-e $file) { +		$s = cat_($file); +		$s = $s =~ /^Description=(.*)/mg ? $1 : ''; +	} else { +		$file = find { -e $_ } map { "$::prefix$_/$name" } '/etc/rc.d/init.d', '/etc/init.d', '/etc/xinetd.d'; +		$s = cat_($file); +		$s =~ s/\\\s*\n#\s*//mg; +		$s = +			$s =~ /^#\s+(?:Short-)?[dD]escription:\s+(.*?)^(?:[^#]|# {0,2}\S)/sm ? $1 : +			$s =~ /^#\s*(.*?)^[^#]/sm ? $1 : ''; + +		$s =~ s/#\s*//mg; +	}      }      $s =~ s/\n/ /gm; $s =~ s/\s+$//;      $s; @@ -148,16 +169,18 @@ sub ask_ {  			 # FIXME: split part of 'Internet' into 'Security' or 'Firewall'?  			 N("Internet") => [ qw(adsl boa cddbp ftp httpd ibod ip6tables ippl iptables iptoip ipvsadm                                                 isdn4linux jabber jabber-icq jail.init junkbuster mandi nessusd pftp portsentry  -                                               prelude proftpd proftpd-xinetd pure-ftpd ipsec radvd roxen shorewall squid +                                               prelude proftpd proftpd-xinetd pure-ftpd ipsec radvd roxen rsyncd shorewall shorewall6 squid                                                 tftp) ], -			 N("_: Keep these entry short\nNetworking") => [ qw(network network-auth network-up resolvconf) ], +			 N("_: Keep these entry short\nNetworking") => [ qw(ModemManager NetworkManager NetworkManager-dispatcher NetworkManager-wait-online +                                                                            arp-ethers network network-auth network-up resolvconf systemd-networkd systemd-resolved) ], -			 N("System") => [ qw(acon acpid alsa anacron apcupsd apmd atd bpowerd bpowerfail crond cvs dm fcron functions +			 N("System") => [ qw(acon acpid alsa anacron apcupsd apmd atd bpowerd bpowerfail cpupower crond cvs dm fcron functions                                               gpm halt harddrake inetd irda jserver keytable kheader killall mageia_everytime -                                             mageia_firstime mdadm medusa-init messagebus microcode_ctl mosix netconsole numlock partmon -                                             pcmcia portmap powertweak.init psacct -                                             random rawdevices rpcbind sensors single sound syslog syslog-ng ups usb usbd wine xfs xinetd) ], +                                             mandrake_firstime mdadm messagebus microcode_ctl mga-bg-res netconsole numlock partmon +                                             pcmcia portmap psacct +                                             random rawdevices rpcbind rtkit-daemon sensors single sound spice-vdagentd +                                             syslog syslog-ng systemd-journal-upload systemd-timesyncd ups wine xfs xinetd) ],  			 N("Remote Administration") => [ qw(cfd drakxtools_http heartbeat iplog ldirectord mon netsaint olympusd rexec                                                              rlogin rsh sshd telnet telnetd vncserver webmin) ], @@ -184,8 +207,13 @@ sub ask_ {  			       node_state => sub { $services{$_[0]} ? 'selected' : 'unselected' },  			       build_tree => sub {  				   my ($add_node, $flat) = @_; +				   # sort existing services by category, putting "Other" at end +				   my @srvs = grep { $services{$_} } map { @{$root_services{$_}} } +						     sort { $a cmp $b } keys %root_services; +				   # put "Others" last: +				   push @srvs, difference2([ keys %services ], \@srvs);  				   $add_node->($_, !$flat && ($services_root{$_} || N("Other"))) -				     foreach sort keys %services; +				     foreach @srvs;  			       },  			       grep_unselected => sub { grep { !$services{$_} } @_ },  			       toggle_nodes => sub { @@ -203,9 +231,7 @@ sub ask_ {  			       },  			       get_info => sub { formatLines(description($_[0])) },                                 interactive_help => sub {  -                                   interactive::gtk::display_help($in, -                                                               { interactive_help_id =>  -                                                                   'misc-params#drakxid-configureServices' }, $::main_window) }, +                                   interactive::gtk::display_help($in, { interactive_help_id => 'configureServices' }) },  			      }) or return $l, $on_services; #- no change on cancel.      [ grep { $services{$_} } @$l ];  } @@ -213,47 +239,34 @@ sub ask_ {  sub ask_standalone_gtk {      my ($_in) = @_;      my ($l, $on_services) = services(); -    my @xinetd_services = map { $_->[0] } @{(services_raw())[1]}; - -    require ugtk2; -    ugtk2->import(qw(:wrappers :create)); - -    my $W = ugtk2->new(N("Services")); -    my ($x, $y, $w_popup); -    my $nopop = sub { $w_popup and $w_popup->destroy; undef $w_popup }; -    my $display = sub {  -	my ($text) = @_; -	$nopop->();  -	gtkshow(gtkadd($w_popup = Gtk2::Window->new('popup'), -		       gtksignal_connect(gtkadd(Gtk2::EventBox->new, -						gtkadd(gtkset_shadow_type(Gtk2::Frame->new, 'etched_out'), -						       gtkset_justify(Gtk2::Label->new($text), 'left'))), -					 button_press_event => sub { $nopop->() } -					)))->move($x, $y) if $text; -    }; +    my @xinetd_services = map { $_->[0] } xinetd_services(); + +    require ugtk3; +    ugtk3->import(qw(:wrappers :create)); + +    my $W = ugtk3->new(N("Services"));      my $update_service = sub {  	my ($service, $label) = @_; -	my $started = -e "/var/lock/subsys/$service"; +	my $started = is_service_running($service);  	$label->set_label($started ? N("running") : N("stopped"));      }; -    my $b = Gtk2::EventBox->new; -    $b->set_events('pointer_motion_mask'); +    my $b = Gtk3::EventBox->new; +    $b->set_events(${ Gtk3::Gdk::EventMask->new("pointer_motion_mask") });      gtkadd($W->{window}, gtkadd($b, gtkpack_($W->create_box_with_title, -	0, mygtk2::gtknew('Title1', label => N("Services and daemons")), +	0, mygtk3::gtknew('Title1', label => N("Services and daemons")),  	1, gtkset_size_request(create_scrolled_window(create_packtable({ col_spacings => 10, row_spacings => 3 },  	    map {                  my $service = $_;  		my $is_xinetd_service = member($service, @xinetd_services);          	my $infos = warp_text(description($_), 40);                  $infos ||= N("No additional information\nabout this service, sorry."); -		my $label = gtkset_justify(Gtk2::Label->new, 'left'); +		my $label = gtkset_justify(Gtk3::Label->new, 'left');                  $update_service->($service, $label) if !$is_xinetd_service; -		[ gtkpack__(Gtk2::HBox->new(0,0), $_), -		  gtkpack__(Gtk2::HBox->new(0,0), $label), -		  gtkpack__(Gtk2::HBox->new(0,0), gtksignal_connect(Gtk2::Button->new(N("Info")), clicked => sub { $display->($infos) })), +		[ gtkpack__(Gtk3::HBox->new(0,0), gtkset_tip(Gtk3::Label->new($_), $infos)), +		  gtkpack__(Gtk3::HBox->new(0,0), $label), -                  gtkpack__(Gtk2::HBox->new(0,0), gtkset_active(gtksignal_connect( -                          Gtk2::CheckButton->new($is_xinetd_service ? N("Start when requested") : N("On boot")), +                  gtkpack__(Gtk3::HBox->new(0,0), gtkset_active(gtksignal_connect( +                          Gtk3::CheckButton->new($is_xinetd_service ? N("Start when requested") : N("On boot")),                            clicked => sub { if ($_[0]->get_active) {                                                 push @$on_services, $service if !member($service, @$on_services);                                             } else { @@ -261,27 +274,19 @@ sub ask_standalone_gtk {                                          } }), member($service, @$on_services))),  		  map {   		      my $a = $_; -		      gtkpack__(Gtk2::HBox->new(0,0), gtksignal_connect(Gtk2::Button->new(translate($a)), +		      gtkpack__(Gtk3::HBox->new(0,0), gtksignal_connect(Gtk3::Button->new(translate($a)),                            clicked => sub {   			      my $action = $a eq "Start" ? 'restart' : 'stop';  -			      log::explanations(qq(GP_LANG="UTF-8" service $service $action)); -			      # as we need the output in UTF-8, force it -			      local $_ = `GP_LANG="UTF-8" service $service $action 2>&1`; s/\033\[[^mG]*[mG]//g; -			      c::set_tagged_utf8($_); +			      _run_action($service, $action);  			      $update_service->($service, $label); -			      $display->($_);  			  })) if !$is_xinetd_service;  		  } (N_("Start"), N_("Stop"))  		];  	    }              @$l), [ $::isEmbedded ? 'automatic' : 'never', 'automatic' ]), -1, $::isEmbedded ? -1 : 400), -            0, gtkpack(gtkset_border_width(Gtk2::HBox->new(0,0),5), $W->create_okcancel) +            0, gtkpack(gtkset_border_width(Gtk3::HBox->new(0,0),5), $W->create_okcancel)              ))  	  ); -    $b->signal_connect(motion_notify_event => sub { my ($w, $e) = @_; -						    my ($ox, $oy) = $w->window->get_origin; -						    $x = $e->x+$ox; $y = $e->y+$oy }); -    $b->signal_connect(button_press_event => sub { $nopop->() });      $::isEmbedded and gtkflush();      $W->main or return;      $on_services; @@ -295,27 +300,37 @@ sub ask {  sub _set_service {      my ($service, $enable) = @_; -    if (-f "/lib/systemd/system/$service.service") { -      if (-l "/lib/systemd/system/$service.service") { -        $service = basename(readlink("/lib/systemd/system/$service.service")); -      } -      else { -        $service = $service . ".service";  -      } -      run_program::rooted($::prefix, "systemctl", $enable ? "enable" : "disable", $service); +    my @xinetd_services = map { $_->[0] } xinetd_services(); + +    # General Note: We use --no-reload here as this code is sometimes triggered +    # from code at boot and reloading systemd during boot is generally a bit +    # racy just now it seems. +    if (member($service, @xinetd_services)) { +        run_program::rooted($::prefix, "chkconfig", "--no-reload", $enable ? "--add" : "--del", $service); # Probably still a bug here as xinet support in chkconfig shells out to /sbin/service.... +    } elsif (running_systemd() || has_systemd()) { +        my $unit_name = _unit_name($service); +        # systemctl rejects any symlinked units. You have to enabled the real file +        if (-l "/lib/systemd/system/$unit_name") { +            $unit_name = basename(readlink("/lib/systemd/system/$unit_name")); +        } +        run_program::rooted($::prefix, "/bin/systemctl", $enable ? "enable" : "disable", "--no-reload", $unit_name);      } else {          my $script = "/etc/rc.d/init.d/$service"; -        run_program::rooted($::prefix, "chkconfig", $enable ? "--add" : "--del", $service); +        run_program::rooted($::prefix, "chkconfig", "--no-reload", $enable ? "--add" : "--del", $service);          #- FIXME: handle services with no chkconfig line and with no Default-Start levels in LSB header          if ($enable && cat_("$::prefix$script") =~ /^#\s+chkconfig:\s+-/m) { -            run_program::rooted($::prefix, "chkconfig", "--level", "35", $service, "on"); +            run_program::rooted($::prefix, "chkconfig", "--no-reload", "--level", "35", $service, "on");          }      }  }  sub _run_action {      my ($service, $action) = @_; -    run_program::rooted($::prefix, "/etc/rc.d/init.d/$service", $action); +    if (running_systemd()) { +        run_program::rooted($::prefix, '/bin/systemctl', '--no-block', $action, _unit_name($service)); +    } else { +        run_program::rooted($::prefix, "/etc/rc.d/init.d/$service", $action); +    }  }  sub doit { @@ -336,43 +351,114 @@ sub doit {      }  } -sub services_raw() { +sub running_systemd() { +    -d '/run/systemd/system'; +} + +sub has_systemd() { +    run_program::rooted($::prefix, '/bin/rpm', '-q', '--qf', '', 'systemd'); +} + +sub xinetd_services() {      local $ENV{LANGUAGE} = 'C'; -    my (@services, @xinetd_services); -    foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list')) { -	if (my ($xinetd_name, $on_off) = m!^\t(\S+):\s*(on|off)!) { -	    push @xinetd_services, [ $xinetd_name, $on_off eq 'on' ]; -	} elsif (my ($name, $l) = m!^(\S+)\s+(0:(on|off).*)!) { -	    push @services, [ $name, [ $l =~ /(\d+):on/g ] ]; -	} +    my @xinetd_services; +    foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list', '--type', 'xinetd')) { +        if (my ($xinetd_name, $on_off) = m!^\t(\S+):\s*(on|off)!) { +            push @xinetd_services, [ $xinetd_name, $on_off eq 'on' ]; +        }      } -    \@services, \@xinetd_services; +    @xinetd_services;  } -#- returns:  +sub _systemd_services() { +    local $ENV{LANGUAGE} = 'C'; +    my @services; +    log::explanations("Detected systemd. Using systemctl introspection."); +    foreach (run_program::rooted_get_stdout($::prefix, '/bin/systemctl', '--no-legend', '--no-pager', '--full', 'list-unit-files')) { +        my ($name, $type) = m!^(\S+)\.(service|socket|timer)\s+(enabled|disabled|generated)!; +        if ($name) { +            my $unit_name = "$name.$type"; +            # We only look at non-template, non-linked service files in /lib +            # We also check for any non-masked sysvinit files as these are +            # also handled by systemd +            if ($name !~ /.*\@$/g && (-e "$::prefix/lib/systemd/system/$unit_name" or -e "$::prefix/etc/rc.d/init.d/$name") && ! -l "$::prefix/lib/systemd/system/$unit_name") { +                push @services, [ _list_name($name, $type), !!run_program::rooted($::prefix, '/bin/systemctl', '--quiet', 'is-enabled', "$unit_name") ]; +            } +        } +    } +    @services; +} + +sub _legacy_services() { +    local $ENV{LANGUAGE} = 'C'; +    my @services; +    my $has_systemd = has_systemd(); +    if ($has_systemd) { +        # The system is not using systemd but will be at next boot. This +        # is typically the case in the installer. In this mode we must read +        # as much as is practicable from the native systemd unit files and +        # combine that with information from chkconfig regarding legacy sysvinit +        # scripts (which systemd will parse and include when running) +        log::explanations("Detected systemd installed. Using systemctl+chkconfig introspection."); +        @services = _systemd_services(); +    } else { +        log::explanations("Could not detect systemd. Using chkconfig service introspection."); +    } + +    # Regardless of whether we expect to use systemd on next boot, we still +    # need to instrospect information about non-systemd native services. +    my $runlevel; +    my $on_off; +    if (!$::isInstall) { +        $runlevel = (split " ", `/sbin/runlevel`)[1]; +    } +    foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list', '--type', 'sysv')) { +        if (my ($name, $l) = m!^(\S+)\s+(0:(on|off).*)!) { +            # If we expect to use systemd (i.e. installer) only show those +            # sysvinit scripts which are not masked by a native systemd unit. +            my $has_systemd_unit = systemd_unit_exists($name); +            if (!$has_systemd || !$has_systemd_unit) { +                if ($::isInstall) { +                    $on_off = $l =~ /\d+:on/g; +                } else { +                    $on_off = $l =~ /$runlevel:on/g; +                } +                push @services, [ $name, $on_off ]; +            } +        } +    } +    @services; +} + +#- returns:  #--- the listref of installed services  #--- the listref of "on" services  sub services() { -    my ($services, $xinetd_services) = services_raw(); -    my @l = @$xinetd_services; -    if ($::isInstall) { -        push @l, map { [ $_->[0], @{$_->[1]} > 0 ] } @$services; +    my @services; +    if (running_systemd()) { +        @services = _systemd_services();      } else { -        my $runlevel = (split " ", `/sbin/runlevel`)[1]; -        push @l, map { [ $_->[0], member($runlevel, @{$_->[1]}) ] } @$services; +        @services = _legacy_services();      } + +    my @l = xinetd_services(); +    push @l, @services;      @l = sort { $a->[0] cmp $b->[0] } @l;      [ map { $_->[0] } @l ], [ map { $_->[0] } grep { $_->[1] } @l ];  } - - +sub systemd_unit_exists { +    my ($name) = @_; +    my $unit_name = _unit_name($name); +    # we test with -l as symlinks are not valid when the system is chrooted: +    -e "$::prefix/lib/systemd/system/$unit_name" or -l "$::prefix/lib/systemd/system/$unit_name"; +}  sub service_exists {      my ($service) = @_; -    -x "$::prefix/etc/rc.d/init.d/$service"; +    -x "$::prefix/etc/rc.d/init.d/$service" or systemd_unit_exists($service);  }  sub restart ($) { @@ -414,7 +500,11 @@ sub is_service_running ($) {      my ($service) = @_;      # Exit silently if the service is not installed      service_exists($service) or return 1; -    run_program::rooted($::prefix, "/etc/rc.d/init.d/$service", '>', '/dev/null', '2>', '/dev/null', "status"); +    if (running_systemd()) { +        run_program::rooted($::prefix, '/bin/systemctl', '--quiet', 'is-active', _unit_name($service)); +    } else { +        run_program::rooted($::prefix, '/sbin/service', $service, 'status'); +    }  }  sub starts_on_boot { | 
