Merge branch 'master' of github.com:webmin/webmin
Some checks are pending
Tests / prove (push) Waiting to run
Package and upload artifacts / build (push) Waiting to run

This commit is contained in:
Jamie Cameron
2026-08-06 14:51:06 -07:00
5 changed files with 112 additions and 2 deletions

View File

@@ -41,6 +41,7 @@ if ($product) {
&flush_file_lines($temp);
copy_source_dest($temp, "$systemd_root/$product.service");
&set_ownership_permissions(0, 0, 0644, "$systemd_root/$product.service");
$reload_daemon->();
if ($status eq "disabled") {
@@ -70,7 +71,7 @@ if ($product) {
}
&flush_file_lines($temp);
&copy_source_dest($temp, "/etc/init.d/$product");
chmod(0755, "/etc/init.d/$product");
&set_ownership_permissions(0, 0, 0755, "/etc/init.d/$product");
&unlink_file($temp);
if ($status == 2 || $want_boot) {
&enable_at_boot($product);
@@ -99,6 +100,7 @@ if ($product) {
}
elsif (-d "/etc/init.d") {
copy_source_dest("$root_directory/webmin-init", "/etc/init.d/$product");
&set_ownership_permissions(0, 0, 0755, "/etc/init.d/$product");
system("chkconfig --add $product >/dev/null 2>&1");
}
}

View File

@@ -2552,6 +2552,32 @@ my $out = backquote_logged($cmd." 2>&1 </dev/null");
return (!$?, $out);
}
=head2 global_user_systemctl_command(arg, ...)
Returns a quoted systemctl command line for changing global user-unit policy.
=cut
sub global_user_systemctl_command
{
my (@args) = @_;
my $systemctl = has_command("systemctl") || "systemctl";
return join(" ", quotemeta($systemctl), "--global",
map { quotemeta($_) } @args);
}
=head2 run_global_user_systemctl(arg, ...)
Runs systemctl --global, returning an OK flag and command output.
=cut
sub run_global_user_systemctl
{
my (@args) = @_;
my $cmd = global_user_systemctl_command(@args);
my $out = backquote_logged($cmd." 2>&1 </dev/null");
return (!$?, $out);
}
=head2 reload_user_manager(user)
Tells a user's systemd manager to re-read its unit files.
@@ -3350,6 +3376,32 @@ my $out = backquote_logged(
return (!$?, $out);
}
=head2 enable_global_user_unit(name)
Enables a systemd user unit globally for all user managers.
=cut
sub enable_global_user_unit
{
my ($name) = @_;
return (0, $text{'systemd_ename'}) if (!valid_unit_name($name));
my ($ok, $out) = run_global_user_systemctl("enable", $name);
return ($ok && !startup_change_skipped($out), $out);
}
=head2 disable_global_user_unit(name)
Disables a globally-enabled systemd user unit for all user managers.
=cut
sub disable_global_user_unit
{
my ($name) = @_;
return (0, $text{'systemd_ename'}) if (!valid_unit_name($name));
my ($ok, $out) = run_global_user_systemctl("disable", $name);
return ($ok && !startup_change_skipped($out), $out);
}
=head2 enable_user_unit(user, name)
Enable a systemd user unit.

View File

@@ -1716,6 +1716,47 @@ like(get_unit_root(), qr{^/(etc|usr/lib|lib)/systemd/system$},
'reload_user_manager reloads the user manager');
}
{
my @cmds;
local *main::has_command = sub {
return $_[0] eq 'systemctl' ? '/bin/systemctl' : undef;
};
local *main::backquote_logged = sub {
push(@cmds, $_[0]);
$? = 0;
return 'ran';
};
my ($ok, $out) = run_global_user_systemctl(
'is-enabled', 'demo.service');
ok($ok, 'run_global_user_systemctl reports command success');
is($out, 'ran', 'run_global_user_systemctl returns command output');
is($cmds[-1],
quotemeta('/bin/systemctl').' --global '.quotemeta('is-enabled').' '.
quotemeta('demo.service').' 2>&1 </dev/null',
'global user systemctl command uses global scope and quotes arguments');
}
{
my @run;
local *main::run_global_user_systemctl = sub {
push(@run, [ @_ ]);
return (1, 'ok');
};
my ($ok) = enable_global_user_unit('demo.service');
ok($ok, 'enable_global_user_unit reports success');
is_deeply($run[-1], [ 'enable', 'demo.service' ],
'enable_global_user_unit arguments');
($ok) = disable_global_user_unit('demo.service');
ok($ok, 'disable_global_user_unit reports success');
is_deeply($run[-1], [ 'disable', 'demo.service' ],
'disable_global_user_unit arguments');
my $before_invalid = scalar(@run);
($ok) = enable_global_user_unit('bad;touch.service');
ok(!$ok, 'global user enable rejects invalid unit names');
is(scalar(@run), $before_invalid,
'invalid global user unit name builds no systemctl command');
}
{
my @run;
local *main::run_user_systemctl = sub {

View File

@@ -228,6 +228,14 @@ subtest 'parse_xml_value' => sub {
'<array><data><value><int>1</int></value><value><string>x</string></value></data></array>'));
is(ref($a), 'ARRAY', 'array -> arrayref');
is_deeply($a, [1, 'x'], 'array elements parsed in order');
# Scalar tags must retain their type when a nested value is later encoded.
require JSON::PP;
my $typed = parse_xml_value(value_tree(
'<struct><member><name>integer</name><value><int>1800</int></value></member><member><name>boolean</name><value><boolean>1</boolean></value></member><member><name>double</name><value><double>2.5</double></value></member><member><name>string</name><value><string>1800</string></value></member></struct>'));
is(JSON::PP->new->canonical->encode($typed),
'{"boolean":1,"double":2.5,"integer":1800,"string":"1800"}',
'nested scalar types preserved for JSON');
};
# Round-trip: encode_xml_value then parse_xml_value should reproduce the

View File

@@ -18,7 +18,14 @@ my ($base64) = &find_xmls("base64", $value, 1);
my ($struct) = &find_xmls("struct", $value, 1);
my ($array) = &find_xmls("array", $value, 1);
if ($scalar) {
return $scalar->[1]->[2] // "";
my ($type, $content) = ($scalar->[0], $scalar->[1]->[2] // "");
$type = lc($type);
return int($content) if ($type eq "int" || $type eq "i4");
return $content ? 1 : 0 if ($type eq "boolean");
return $content + 0.0 if ($type eq "double");
return $content;
}
elsif ($date) {
# Need to decode date