#!/usr/bin/env perl
# set-config - Set a Webmin configuration option to the value provided and
# restart Webmin to apply the change.
use strict;
use warnings;
BEGIN { $Pod::Usage::Formatter = 'Pod::Text::Color'; }
use 5.010; # Version in CentOS 6
use Getopt::Long qw(:config permute pass_through);
use Pod::Usage;
use Term::ANSIColor qw(:constants);
use Fcntl qw( :flock );
sub main {
my %opt;
GetOptions(
'help|h' => \$opt{'help'},
'config|c=s' => \$opt{'config'},
'module|m=s' => \$opt{'module'},
'option|o=s' => \$opt{'option'},
'value|v=s' => \$opt{'value'},
'force|f' => \$opt{'force'}
);
pod2usage(0) if ( $opt{'help'} );
$opt{'config'} ||= "/etc/webmin";
set_config( \%opt );
return 0;
}
exit main( \@ARGV ) if !caller(0);
sub set_config {
my ($optref) = @_;
my $key = $optref->{'option'};
my $value = $optref->{'value'};
$key or die RED, "An --option must be specified", RESET;
my @config_lines;
# Module or root-level config?
my $config_file;
if ($optref->{'module'}) {
$config_file = "$optref->{'config'}/$optref->{'module'}/config";
} else {
$config_file = "$optref->{'config'}/miniserv.conf";
}
# Read'em
open my $fh, '+<', $config_file
or die RED, "Unable to open $config_file", RESET;
flock($fh, LOCK_EX) or die RED, "Unable to lock $config_file", RESET;
chomp(@config_lines = <$fh>);
# Change'em
my $found = 0;
my $exit_code = 0;
# Validate it against the config.info if this is a module and
if ($optref->{'module'} && !($optref->{'force'})) {
validate_config_option($optref);
}
for (@config_lines) {
if (/^${key}=(.*)/) {
s/^${key}=(.*)/${key}=${value}/;
$found++;
}
}
unless ($found > 0) {
push(@config_lines, "$key=$value");
$exit_code++;
}
# Write'em
seek($fh, 0, 0);
print $fh qq|$_\n| for @config_lines;
close $fh;
# Restart Webmin if editing miniserv.conf
unless ($optref->{'module'}) {
say "Restarting Webmin to apply miniserv.conf changes...";
system("$optref->{'config'}/restart");
}
exit $exit_code;
}
sub validate_config_option {
my ($optref) = @_;
my $root = root($optref->{'config'});
my $key = $optref->{'option'};
# Load the config.info
open my $fh, '<', "$root/$optref->{'module'}/config.info";
# Does this key exist?
my $found;
while (<$fh>) {
if (/^${key}=(.*)/) {
$found++;
}
}
close $fh;
$found or
die RED, "Option '$key' is unknown in module $optref->{'module'}", RESET;
return 1;
}
sub root {
my ($config) = @_;
open(my $CONF, "<", "$config/miniserv.conf") || die RED,
"Failed to open $config/miniserv.conf", RESET;
my $root;
while (<$CONF>) {
if (/^root=(.*)/) {
$root = $1;
}
}
close($CONF);
# Does the Webmin root exist?
if ( $root ) {
die "$root is not a directory. Is --config correct?" unless (-d $root);
} else {
die "Unable to determine Webmin installation directory from $ENV{'WEBMIN_CONFIG'}";
}
return $root;
}
1;
=pod
=head1 NAME
set-config
=head1 DESCRIPTION
Set a configuration directive in either C<miniserv.conf> (the core Webmin config) or in the specified module C<config>.
=head1 SYNOPSIS
webmin set-config [options] [--module] --option <option-name> --value <value>
=head1 OPTIONS
=over
=item --help, -h
Print this usage summary and exit.
=item --config, -c
Specify the full path to the Webmin configuration directory. Defaults to
C</etc/webmin>
=item --module, -m
Specify which module configuration to modify. If none given, configuration will be assumed to be the Webmin core configuration (/etc/webmin/miniserv.conf).
=item --option, -o
Specify the option to change.
=item --value, -v
The value to change the option to.
=item --force, -f
Skip validation of the option name. Allows modifying hidden options, and adding unknown options.
=back
=head1 EXIT CODES
0 on successfully replacing a config variable
1 on successfully adding a new config variable (the specified option did not
already exist in the file, and was added)
>1 on error
=head1 LICENSE AND COPYRIGHT
Copyright 2018 Jamie Cameron <jcameron@webmin.com>
Joe Cooper <joe@virtualmin.com>