diff --git a/init/atboot.pl b/init/atboot.pl index 798386f3c..d2734ba41 100755 --- a/init/atboot.pl +++ b/init/atboot.pl @@ -126,6 +126,11 @@ elsif ($init_mode eq "rc" || $init_mode eq "upstart" || { 'fork' => 1, 'pidfile' => $var_directory."/miniserv.pid" }); } +elsif ($init_mode eq "launchd") { + # Create launchd script + &create_launchd_agent(&launchd_name($product), + "$config_directory/start --nofork", 1); + } $config{'atboot_product'} = $product; &save_module_config(); diff --git a/init/edit_launchd.cgi b/init/edit_launchd.cgi index eaf3e0f96..4c177d61f 100755 --- a/init/edit_launchd.cgi +++ b/init/edit_launchd.cgi @@ -69,6 +69,7 @@ else { [ 'start', $text{'edit_startnow'} ], [ 'restart', $text{'edit_restartnow'} ], [ 'stop', $text{'edit_stopnow'} ], + [ 'reload', $text{'edit_reloadnow2'} ], [ 'delete', $text{'delete'} ] ]); } diff --git a/init/init-lib.pl b/init/init-lib.pl index af97b9223..9341dafb0 100755 --- a/init/init-lib.pl +++ b/init/init-lib.pl @@ -512,12 +512,13 @@ such as init.d, OSX and FreeBSD. =cut sub action_status { +my ($name) = @_; if ($init_mode eq "upstart") { # Check upstart service status local $out = &backquote_command("initctl status ". - quotemeta($_[0])." 2>&1"); + quotemeta($name)." 2>&1"); if (!$?) { - my $cfile = "/etc/init/$_[0].conf"; + my $cfile = "/etc/init/$name.conf"; open(CONF, $cfile); while() { if (/^(#*)\s*start/) { @@ -530,7 +531,7 @@ if ($init_mode eq "upstart") { } elsif ($init_mode eq "systemd") { # Check systemd service status - local $unit = $_[0]; + local $unit = $name; $unit .= ".service" if ($unit !~ /\.service$/); local $out = &backquote_command("systemctl show ". quotemeta($unit)." 2>&1"); @@ -546,7 +547,7 @@ if ($init_mode eq "init" || $init_mode eq "upstart" || local ($a, $exists, $starting, %daemon); foreach $a (&list_actions()) { local @a = split(/\s+/, $a); - if ($a[0] eq $_[0]) { + if ($a[0] eq $name) { $exists++; local @boot = &get_inittab_runlevel(); foreach $s (&action_levels("S", $a[0])) { @@ -556,14 +557,14 @@ if ($init_mode eq "init" || $init_mode eq "upstart" || } } if ($starting && $config{'daemons_dir'} && - &read_env_file("$config{'daemons_dir'}/$_[0]", \%daemon)) { + &read_env_file("$config{'daemons_dir'}/$name", \%daemon)) { $starting = lc($daemon{'ONBOOT'}) eq 'yes' ? 1 : 0; } return !$exists ? 0 : $starting ? 2 : 1; } elsif ($init_mode eq "local") { # Look for entry in rc.local - local $fn = "$module_config_directory/$_[0].sh"; + local $fn = "$module_config_directory/$name.sh"; local $cmd = "$fn start"; open(LOCAL, $config{'local_script'}); while() { @@ -575,20 +576,20 @@ elsif ($init_mode eq "local") { } elsif ($init_mode eq "win32") { # Look for a win32 service, enabled at boot - local ($svc) = &list_win32_services($_[0]); + local ($svc) = &list_win32_services($name); return !$svc ? 0 : $svc->{'boot'} == 2 ? 2 : 1; } elsif ($init_mode eq "rc") { # Look for an RC script local @rcs = &list_rc_scripts(); - local ($rc) = grep { $_->{'name'} eq $_[0] } @rcs; + local ($rc) = grep { $_->{'name'} eq $name } @rcs; return !$rc ? 0 : $rc->{'enabled'} ? 2 : 1; } elsif ($init_mode eq "osx") { # Look for a hostconfig entry - local $ucname = uc($_[0]); + local $ucname = uc($name); local %hc; &read_env_file($config{'hostconfig'}, \%hc); return $hc{$ucname} eq '-YES-' ? 2 : @@ -596,7 +597,7 @@ elsif ($init_mode eq "osx") { } elsif ($init_mode eq "launchd") { local @agents = &list_launchd_agents(); - local ($agent) = grep { $_->{'name'} eq $_[0] } @agents; + local ($agent) = grep { $_->{'name'} eq &launchd_name($name) } @agents; return !$agent ? 0 : $agent->{'boot'} ? 2 : 1; } @@ -983,7 +984,28 @@ elsif ($init_mode eq "osx") { } elsif ($init_mode eq "launchd") { # Create and if necessary enable a launchd agent - # XXX + my $name = &launchd_name($_[0]); + my @agents = &list_launchd_agents(); + my ($agent) = grep { $_->{'name'} eq $name } @agents; + if (!$agent) { + # Need to create script + &create_launchd_agent($name, $_[1], 1); + } + else { + # Just enable at boot + my $out = &read_file_contents($agent->{'file'}); + if ($out =~ /RunAtLoad<\/key>/i) { + # Just fix setting + $out =~ s/RunAtLoad<\/key>\s*<(true|false)\/>/RunAtLoad<\/key>\n/; + } + else { + # Defaults to false, so need to add before + $out =~ s/<\/plist>/RunAtLoad<\/key>\n\n<\/plist>/; + } + &open_lock_tempfile(PLIST, ">$agent->{'file'}"); + &print_tempfile(PLIST, $out); + &close_tempfile(PLIST); + } } } @@ -996,6 +1018,7 @@ touched, so it can be re-enabled with the enable_at_boot function. =cut sub disable_at_boot { +my ($name) = @_; local $st = &action_status($_[0]); return if ($st != 2); # not currently starting local $unit = $_[0]; @@ -1119,7 +1142,15 @@ elsif ($init_mode eq "osx") { } elsif ($init_mode eq "launchd") { # Adjust plist file to not run at boot - # XXX + my @agents = &list_launchd_agents(); + my ($a) = grep { $_->{'name'} eq &launchd_name($name) } @agents; + if ($a && $a->{'file'}) { + my $out = &read_file_contents($a->{'file'}); + $out =~ s/RunAtLoad<\/key>\s*<(true|false)\/>/RunAtLoad<\/key>\n/; + &open_lock_tempfile(PLIST, ">$a->{'file'}"); + &print_tempfile(PLIST, $out); + &close_tempfile(PLIST); + } } } @@ -1143,7 +1174,7 @@ elsif ($mode eq "upstart") { } elsif ($mode eq "launchd") { # Delete launchd service - &delete_launchd_agent($name); + &delete_launchd_agent(&launchd_name($name)); } elsif ($mode eq "init") { # Delete init script links and init.d file @@ -1229,7 +1260,7 @@ elsif ($action_mode eq "systemd") { } elsif ($action_mode eq "launchd") { # Start launchd service - return &start_launchd_agent($name); + return &start_launchd_agent(&launchd_name($name)); } else { return (0, "Bootup mode $action_mode not supported"); @@ -1277,7 +1308,7 @@ elsif ($action_mode eq "systemd") { } elsif ($action_mode eq "launchd") { # Stop launchd service - return &stop_launchd_agent($name); + return &stop_launchd_agent(&launchd_name($name)); } else { return (0, "Bootup mode $action_mode not supported"); @@ -1339,7 +1370,7 @@ elsif ($action_mode eq "systemd") { } elsif ($action_mode eq "launchd") { my @agents = &list_launchd_agents(); - my ($a) = grep { $_->{'name'} eq $name } @agents; + my ($a) = grep { $_->{'name'} eq &launchd_name($name) } @agents; return !$u ? -1 : $u->{'status'} ? 1 : 0; } else { @@ -2412,4 +2443,12 @@ my $out = &backquote_logged( return (!$?, $out); } +# launchd_name(name) +# If an action name isn't fully qualified, prepend com.webmin to it +sub launchd_name +{ +my ($name) = @_; +return $name =~ /\./ ? $name : "com.webmin.".$name; +} + 1; diff --git a/init/lang/en b/init/lang/en index ed7842c88..b9d4ae6b0 100644 --- a/init/lang/en +++ b/init/lang/en @@ -79,6 +79,7 @@ edit_stopat=Stop at edit_startnow=Start Now edit_stopnow=Stop Now edit_restartnow=Restart Now +edit_reloadnow2=Re-Read Config File edit_condrestartnow=Restart If Needed edit_reloadnow=Reload Now edit_statusnow=Show Status diff --git a/init/save_launchd.cgi b/init/save_launchd.cgi index 3efd9d415..7b96d1b04 100755 --- a/init/save_launchd.cgi +++ b/init/save_launchd.cgi @@ -27,6 +27,12 @@ if ($in{'delete'}) { &delete_launchd_agent($in{'name'}); &webmin_log("delete", "launchd", $in{'name'}); } +elsif ($in{'reload'}) { + # Re-load the service from its config file + &system_logged("launchctl unload ".quotemeta($u->{'file'})." 2>&1"); + &system_logged("launchctl load ".quotemeta($u->{'file'})." 2>&1"); + &webmin_log("reload", "launchd", $in{'name'}); + } elsif ($in{'new'}) { # Validate inputs and check for clash $in{'name'} =~ /^[a-z0-9\.\_\-]+$/i || @@ -47,19 +53,6 @@ else { &open_lock_tempfile(CONF, ">$u->{'file'}"); &print_tempfile(CONF, $in{'conf'}); &close_tempfile(CONF); - &system_logged("launchctl unload ".quotemeta($u->{'file'})." 2>&1"); - &system_logged("launchctl load ".quotemeta($u->{'file'})." 2>&1"); - - # Enable or disable - if (defined($in{'boot'})) { - if ($in{'boot'} == 0) { - &disable_at_boot($in{'name'}); - } - else { - &enable_at_boot($in{'name'}); - } - } - &webmin_log("modify", "launchd", $in{'name'}); } &redirect("");