) {
/^(\S+):(\S+)/;
push(@{$_[1]}, $1); $_[2]->{$1} = $2;
}
close(USERS);
}
# config_icons(context, program)
# Displays up to 18 icons, one for each type of configuration directive, for
# some context (global, virtual, directory or htaccess)
sub config_icons
{
local ($ctx, $prog) = @_;
local($m, $func, $e, %etype, $i, $c);
foreach $m (sort { $a cmp $b } (keys %httpd_modules)) {
$func = $m."_directives";
if (defined(&$func)) {
foreach $e (&$func($httpd_modules{$m})) {
if ($e->{$ctx}) { $etype{$e->{'type'}}++; }
}
}
}
local (@titles, @links, @icons);
for($i=0; $text{"type_$i"}; $i++) {
if ($etype{$i} && $access_types{$i}) {
push(@links, $prog."type=$i");
push(@titles, $text{"type_$i"});
push(@icons, "images/type_icon_$i.gif");
}
}
for($i=2; $i<@_; $i++) {
if ($_[$i]) {
push(@links, $_[$i]->{'link'});
push(@titles, $_[$i]->{'name'});
push(@icons, $_[$i]->{'icon'});
}
}
&icons_table(\@links, \@titles, \@icons, 5);
print "\n";
}
# restart_button()
# Returns HTML for a link to put in the top-right corner of every page
sub restart_button
{
local $args = "redir=".&urlize(&this_url());
local @rv;
if (&is_apache_running()) {
if ($access{'apply'}) {
my $n = &needs_config_restart();
if ($n) {
push(@rv, &ui_link("restart.cgi?$args&newconfig=1",
"$text{'apache_apply'}") );
}
else {
push(@rv, &ui_link("restart.cgi?$args", $text{'apache_apply'}) );
}
}
if ($access{'stop'}) {
push(@rv, &ui_link("stop.cgi?$args", $text{'apache_stop'}) );
}
}
elsif ($access{'stop'}) {
push(@rv, &ui_link("start.cgi?$args", $text{'apache_start'}) );
}
return join("
\n", @rv);
}
# this_url()
# Returns the URL in the apache directory of the current script
sub this_url
{
local($url);
$url = $ENV{'SCRIPT_NAME'};
if ($ENV{'QUERY_STRING'} ne "") { $url .= "?$ENV{'QUERY_STRING'}"; }
return $url;
}
# find_all_directives(config, name)
# Recursively finds all directives of some type
sub find_all_directives
{
local(@rv, $d);
foreach $d (@{$_[0]}) {
if ($d->{'name'} eq $_[1]) { push(@rv, $d); }
if ($d->{'type'} == 1) {
push(@rv, &find_all_directives($d->{'members'}, $_[1]));
}
}
return @rv;
}
# httpd_info(executable)
# Returns the httpd version and modules array
sub httpd_info
{
local ($cmd) = @_;
$cmd = &has_command($cmd);
local @st = stat($cmd);
local %cache;
&read_file_cached($httpd_info_cache, \%cache);
if ($cache{'cmd'} eq $cmd && $cache{'time'} == $st[9]) {
# Cache looks up to date
return ($cache{'version'}, [ split(/\s+/, $cache{'mods'}) ],
$cache{'fullversion'});
}
local(@mods, $verstr, $ver, $minor, $fullver);
$verstr = &backquote_command(quotemeta($cmd)." -v 2>&1");
if ($config{'httpd_version'} =~ /(\d+)\.([\d\.]+)/) {
$fullver = $config{'httpd_version'};
$ver = $1;
$minor = $2;
$minor =~ s/\.//g;
$ver .= ".$minor";
}
elsif ($verstr =~ /Apache(\S*)\/(\d+)\.([\d\.]+)/) {
# standard apache
$fullver = "$2.$3";
$ver = $2;
$minor = $3;
$minor =~ s/\.//g;
$ver .= ".$minor";
}
elsif ($verstr =~ /HP\s*Apache-based\s*Web\s*Server(\S*)\/(\d+)\.([\d\.]+)/) {
# HP's apache
$fullver = "$2.$3";
$ver = $2;
$minor = $3;
$minor =~ s/\.//g;
$ver .= ".$minor";
}
elsif ($verstr =~ /Red\s*Hat\s+Secure\/2\.0/i) {
# redhat secure server 2.0
$fullver = $ver = 1.31;
}
elsif ($verstr =~ /Red\s*Hat\s+Secure\/3\.0/i) {
# redhat secure server 3.0
$fullver = $ver = 1.39;
}
elsif (&has_command("rpm") &&
&backquote_command("rpm -q apache 2>&1") =~ /^apache-(\d+)\.([\d\.]+)/) {
# got version from the RPM
$fullver = $ver = $1;
$minor = $2;
$minor =~ s/\.//g;
$ver .= ".$minor";
}
else {
# couldn't get version
return (0, undef);
}
if ($ver < 1.2) {
# apache 1.1 has no -l option! Use the standard list
@mods = ("core", "mod_mime", "mod_access", "mod_auth", "mod_include",
"mod_negotiation", "mod_dir", "mod_cgi", "mod_userdir",
"mod_alias", "mod_env", "mod_log_common");
}
else {
# ask apache for the module list
@mods = ("core");
&open_execute_command(APACHE, "\"$_[0]\" -l 2>/dev/null", 1);
while() {
if (/(\S+)\.c/) { push(@mods, $1); }
}
close(APACHE);
if ($?) {
# httpd crashed! Use last known good set of modules
local %oldsite;
&read_file($site_file, \%oldsite);
if ($oldsite{'modules'}) {
@mods = split(/\s+/, $oldsite{'modules'});
}
}
@mods = &unique(@mods);
}
$cache{'cmd'} = $cmd;
$cache{'time'} = $st[9];
$cache{'version'} = $ver;
$cache{'fullversion'} = $fullver;
$cache{'mods'} = join(" ", @mods);
&write_file($httpd_info_cache, \%cache);
return ($ver, \@mods, $fullver);
}
# print_line(directive, text, indent, link)
sub print_line
{
local $line = $_[0]->{'line'} + 1;
local $lstr = "$_[0]->{'file'} ($line)";
local $txt = join("", @{$_[1]});
local $left = 85 - length($lstr) - $_[2];
if (length($txt) > $left) {
$txt = substr($txt, 0, $left)." ..";
}
local $txtlen = length($txt);
$txt = &html_escape($txt);
print " " x $_[2];
if ($_[3]) {
print &ui_link($_[3], $txt);
}
else { print $txt; }
print " " x (90 - $txtlen - $_[2] - length($lstr));
print $lstr,"\n";
}
# can_edit_virt(struct)
sub can_edit_virt
{
return 1 if ($access{'virts'} eq '*');
local %vcan = map { $_, 1 } split(/\s+/, $access{'virts'});
local ($can) = grep { $vcan{$_} } &virt_acl_name($_[0]);
return $can ? 1 : 0;
}
# virt_acl_name(struct)
# Give a virtual host, returns a list of names that could be used in the ACL
# to refer to it
sub virt_acl_name
{
return ( "__default__" ) if (!$_[0]);
local $n = &find_directive("ServerName", $_[0]->{'members'});
local @rv;
local $p;
if ($_[0]->{'value'} =~ /(:\d+)/) { $p = $1; }
if ($n) {
push(@rv, $n.$p);
}
else {
push(@rv, $_[0]->{'value'});
}
foreach $n (&find_directive_struct("ServerAlias", $_[0]->{'members'})) {
local $a;
foreach $a (@{$n->{'words'}}) {
push(@rv, $a.$p);
}
}
return @rv;
}
# allowed_auth_file(file)
sub allowed_auth_file
{
local $_;
return 1 if ($access{'dir'} eq '/');
return 0 if ($_[0] =~ /\.\./);
local $f = &server_root($_[0], &get_config());
return 0 if (-l $f && !&allowed_auth_file(readlink($f)));
local $l = length($access{'dir'});
return length($f) >= $l && substr($f, 0, $l) eq $access{'dir'};
}
# directory_exists(file)
# Returns 1 if the directory in some path exists
sub directory_exists
{
local $path = &server_root($_[0], &get_config());
if ($path =~ /^(\S*\/)([^\/]+)$/) {
return -d $1;
}
else {
return 0;
}
}
# allowed_doc_dir(dir)
# Returns 1 if some directory is under the allowed root for alias targets
sub allowed_doc_dir
{
return $access{'aliasdir'} eq '/' ||
$_[0] !~ /^\// || # Relative path, like for
&is_under_directory($access{'aliasdir'}, $_[0]);
}
sub lock_apache_files
{
local $conf = &get_config();
local $f;
@main::locked_apache_files = &unique(map { $_->{'file'} } @$conf);
foreach $f (@main::locked_apache_files) {
&lock_file($f);
}
}
sub unlock_apache_files
{
local $conf = &get_config();
local $f;
foreach $f (@main::locked_apache_files) {
&unlock_file($f);
}
@main::locked_apache_files = ( );
}
# directive_lines(directive, ...)
# Convery a list of Apache directives into a list of lines
sub directive_lines
{
my @rv;
foreach my $d (@_) {
next if ($d->{'name'} eq 'dummy');
my $indent = (" " x $d->{'indent'});
if ($d->{'type'}) {
push(@rv, $indent."<$d->{'name'} $d->{'value'}>");
push(@rv, &directive_lines(@{$d->{'members'}}));
push(@rv, $indent."$d->{'name'}>");
}
else {
push(@rv, $indent."$d->{'name'} $d->{'value'}");
}
}
return @rv;
}
# test_config()
# If possible, test the current configuration and return an error message,
# or undef.
sub test_config
{
if ($httpd_modules{'core'} >= 1.301) {
# Test the configuration with the available command
local $cmd;
if ($config{'test_apachectl'} &&
-x &translate_filename($config{'apachectl_path'})) {
# Test with apachectl
$cmd = "\"$config{'apachectl_path'}\" configtest";
}
else {
# Test with httpd
local $httpd = &find_httpd();
$cmd = "\"$httpd\" -d \"$config{'httpd_dir'}\" -t";
if ($config{'httpd_conf'}) {
$cmd .= " -f \"$config{'httpd_conf'}\"";
}
foreach $d (&get_httpd_defines()) {
$cmd .= " -D$d";
}
}
local $out = &backquote_command("$cmd 2>&1");
if ($out && $out !~ /(syntax|Checking).*\s+ok/i) {
return $out;
}
}
return undef;
}
# before_changing()
# If testing all changes, backup the config files so they can be reverted
# if necessary.
sub before_changing
{
if ($config{'test_always'} || $access{'test_always'}) {
local $conf = &get_config();
local @files = &unique(map { $_->{'file'} } @$conf);
local $/ = undef;
local $f;
foreach $f (@files) {
if (&open_readfile(BEFORE, $f)) {
$before_changing{$f} = ;
close(BEFORE);
}
}
}
}
# after_changing()
# If testing all changes, test now and revert the configs and show an error
# message if a problem was found.
sub after_changing
{
if ($config{'test_always'} || $access{'test_always'}) {
local $err = &test_config();
if ($err) {
# Something failed .. revert all files
&rollback_apache_config();
&error(&text('eafter', "$err
"));
}
}
}
# rollback_apache_config()
# Copy back all config files from their originals
sub rollback_apache_config
{
local $f;
foreach $f (keys %before_changing) {
&open_tempfile(AFTER, ">$f");
&print_tempfile(AFTER, $before_changing{$f});
&close_tempfile(AFTER);
}
}
# find_httpd_conf()
# Returns the path to the http.conf file, and the last place looked
# (without any translation).
sub find_httpd_conf
{
local $conf = $config{'httpd_conf'};
return ( -f &translate_filename($conf) ? $conf : undef, $conf ) if ($conf);
$conf = "$config{'httpd_dir'}/conf/httpd.conf";
$conf = "$config{'httpd_dir'}/conf/httpd2.conf"
if (!-f &translate_filename($conf));
$conf = "$config{'httpd_dir'}/etc/httpd.conf"
if (!-f &translate_filename($conf));
$conf = "$config{'httpd_dir'}/etc/httpd2.conf"
if (!-f &translate_filename($conf));
$conf = undef if (!-f &translate_filename($conf));
return ( $conf, "$config{'httpd_dir'}/conf/httpd.conf" );
}
# find_httpd()
# Returns the path to the httpd executable, by appending '2' if necessary
sub find_httpd
{
return $config{'httpd_path'}
if (-x &translate_filename($config{'httpd_path'}) &&
!-d &translate_filename($config{'httpd_path'}));
return $config{'httpd_path'}.'2'
if (-x &translate_filename($config{'httpd_path'}.'2') &&
!-d &translate_filename($config{'httpd_path'}.'2'));
return undef;
}
# get_pid_file()
# Returns the path to the PID file (without any translation)
sub get_pid_file
{
return $config{'pid_file'} if ($config{'pid_file'});
local $conf = &get_config();
local $pidfilestr = &find_directive_struct("PidFile", $conf);
local $pidfile = $pidfilestr ? $pidfilestr->{'words'}->[0]
: "logs/httpd.pid";
return &server_root($pidfile, $conf);
}
# restart_apache()
# Re-starts Apache, and returns undef on success or an error message on failure
sub restart_apache
{
local $pidfile = &get_pid_file();
if ($config{'apply_cmd'} eq 'restart') {
# Call stop and start functions
local $err = &stop_apache();
return $err if ($err);
local $stopped = &wait_for_apache_stop();
local $err = &start_apache();
return $err if ($err);
}
elsif ($config{'apply_cmd'}) {
# Use the configured start command
&clean_environment();
local $out = &backquote_logged("$config{'apply_cmd'} 2>&1");
&reset_environment();
&wait_for_graceful() if ($config{'apply_cmd'} =~ /graceful/);
if ($?) {
return "".&html_escape($out)."
";
}
}
elsif (-x &translate_filename($config{'apachectl_path'})) {
# Use apachectl to restart
if ($httpd_modules{'core'} >= 2) {
# Do a graceful restart
&clean_environment();
local $out = &backquote_logged(
"$config{'apachectl_path'} graceful 2>&1");
&reset_environment();
&wait_for_graceful();
if ($?) {
return "".&html_escape($out)."
";
}
}
else {
&clean_environment();
local $out = &backquote_logged(
"$config{'apachectl_path'} restart 2>&1");
&reset_environment();
if ($out !~ /httpd restarted/) {
return "".&html_escape($out)."
";
}
}
}
else {
# send SIGHUP directly
&open_readfile(PID, $pidfile) || return &text('restart_epid', $pidfile);
=~ /(\d+)/ || return &text('restart_epid2', $pidfile);
close(PID);
&kill_logged('HUP', $1) || return &text('restart_esig', $1);
&wait_for_graceful();
}
&restart_last_restart_time();
return undef;
}
# wait_for_graceful([timeout])
# Wait for some time for Apache to complete a graceful restart
sub wait_for_graceful
{
local $timeout = $_[0] || 10;
local $errorlog = &get_error_log();
return -1 if (!$errorlog || !-r $errorlog);
local @st = stat($errorlog);
my $start = time();
while(time() - $start < $timeout) {
sleep(1);
open(ERRORLOG, "<".$errorlog);
seek(ERRORLOG, $st[7], 0);
local $/ = undef;
local $rest = ;
close(ERRORLOG);
if ($rest =~ /resuming\s+normal\s+operations/i) {
return 1;
}
}
return 0;
}
# stop_apache()
# Attempts to stop the running Apache process, and returns undef on success or
# an error message on failure
sub stop_apache
{
local $out;
if ($config{'stop_cmd'}) {
# use the configured stop command
$out = &backquote_logged("($config{'stop_cmd'}) 2>&1");
if ($?) {
return "".&html_escape($out)."
";
}
}
elsif (-x $config{'apachectl_path'}) {
# use the apachectl program
$out = &backquote_logged("($config{'apachectl_path'} stop) 2>&1");
if ($httpd_modules{'core'} >= 2 ? $? : $out !~ /httpd stopped/) {
return "".&html_escape($out)."
";
}
}
else {
# kill the process
$pidfile = &get_pid_file();
open(PID, "<".$pidfile) || return &text('stop_epid', $pidfile);
=~ /(\d+)/ || return &text('stop_epid2', $pidfile);
close(PID);
&kill_logged('TERM', $1) || return &text('stop_esig', $1);
}
return undef;
}
# start_apache()
# Attempts to start Apache, and returns undef on success or an error message
# upon failure.
sub start_apache
{
local ($out, $cmd);
&clean_environment();
if ($config{'start_cmd'}) {
# use the configured start command
if ($config{'stop_cmd'}) {
# execute the stop command to clear lock files
&system_logged("($config{'stop_cmd'}) >/dev/null 2>&1");
}
$out = &backquote_logged("($config{'start_cmd'}) 2>&1");
&reset_environment();
if ($?) {
return "".&html_escape($out)."
";
}
}
elsif (-x $config{'apachectl_path'}) {
# use the apachectl program
$cmd = "$config{'apachectl_path'} start";
$out = &backquote_logged("($cmd) 2>&1");
&reset_environment();
}
else {
# start manually
local $httpd = &find_httpd();
$cmd = "$httpd -d $config{'httpd_dir'}";
if ($config{'httpd_conf'}) {
$cmd .= " -f $config{'httpd_conf'}";
}
foreach $d (&get_httpd_defines()) {
$cmd .= " -D$d";
}
local $temp = &transname();
local $rv = &system_logged("( $cmd ) >$temp 2>&1 ".&html_escape($cmd)." :\n".
&html_escape($out)."";
}
$slept = 1;
}
# check if startup was successful. Later apache version return no
# error code, but instead fail to start and write the reason to
# the error log file!
sleep(3) if (!$slept);
local $conf = &get_config();
if (!&is_apache_running()) {
# Not running.. find out why
local $errorlogstr = &find_directive_struct("ErrorLog", $conf);
local $errorlog = $errorlogstr ? $errorlogstr->{'words'}->[0]
: "logs/error_log";
if ($out =~ /\S/) {
return "$text{'start_eafter'} : $out
";
}
elsif ($errorlog eq 'syslog' || $errorlog =~ /^\|/) {
return $text{'start_eunknown'};
}
else {
$errorlog = &server_root($errorlog, $conf);
$out = `tail -5 $errorlog`;
return "$text{'start_eafter'} : $out
";
}
}
&restart_last_restart_time();
return undef;
}
# get_error_log()
# Returns the path to the global error log, if possible
sub get_error_log
{
local $conf = &get_config();
local $errorlogstr = &find_directive_struct("ErrorLog", $conf);
local $errorlog = $errorlogstr ? $errorlogstr->{'words'}->[0]
: "logs/error_log";
$errorlog = &server_root($errorlog, $conf);
return $errorlog;
}
sub is_apache_running
{
if ($gconfig{'os_type'} eq 'windows') {
# No such thing as a PID file on Windows
local ($pid) = &find_byname("Apache.exe");
return $pid;
}
else {
# Check PID file
local $pidfile = &get_pid_file();
return &check_pid_file($pidfile);
}
}
# wait_for_apache_stop([secs])
# Wait 30 (by default) seconds for Apache to stop. Returns 1 if OK, 0 if not
sub wait_for_apache_stop
{
local $secs = $_[0] || 30;
for(my $i=0; $i<$secs; $i++) {
return 1 if (!&is_apache_running());
sleep(1);
}
return 0;
}
# configurable_modules([&all-mods])
# Returns a list of Apaches that are compiled in or dynamically loaded, and
# supported by Webmin.
sub configurable_modules
{
my ($allmods) = @_;
$allmods ||= [ &available_modules() ];
return grep { -r "$module_root_directory/$_.pl" } @$allmods;
}
# available_modules()
# Returns a list of Apaches that are compiled in or dynamically loaded
sub available_modules
{
my ($ver, $mods) = &httpd_info(&find_httpd());
my @rv;
# Add compiled-in modules
push(@rv, @$mods);
# Add dynamically loaded modules
my $conf = &get_config();
foreach my $l (&find_directive_struct("LoadModule", $conf)) {
if ($l->{'words'}->[1] =~ /(mod_\S+)\.(so|dll)/) {
push(@rv, $1);
}
elsif ($l->{'words'}->[1] =~ /libssl\.so/) {
push(@rv, "mod_apachessl");
}
elsif ($l->{'words'}->[1] =~ /lib([^\/\s]+)\.(so|dll)/) {
push(@rv, "mod_$1");
}
}
# Add dynamically loaded modules
if ($config{'apachectl_path'}) {
&open_execute_command(APACHE,
"$config{'apachectl_path'} -M 2>/dev/null", 1);
while() {
if (/(\S+)_module/) {
push(@rv, "mod_${1}");
}
}
close(APACHE);
}
return &unique(@rv);
}
# get_httpd_defines(automatic-only)
# Returns a list of defines that need to be passed to Apache
sub get_httpd_defines
{
local ($auto) = @_;
if (@get_httpd_defines_cache) {
return @get_httpd_defines_cache;
}
local @rv;
if (!$auto) {
push(@rv, keys %httpd_defines);
}
if ($config{'defines_file'}) {
# Add defines from an environment file, which can be in
# the format :
# OPTIONS='-Dfoo -Dbar'
# or regular name=value format
local %def;
&read_env_file($config{'defines_file'}, \%def);
if ($config{'defines_name'} && $def{$config{'defines_name'}}) {
# Looking for var like OPTIONS='-Dfoo -Dbar'
local $var = $def{$config{'defines_name'}};
foreach my $v (split(/\s+/, $var)) {
if ($v =~ /^-[Dd](\S+)$/) {
push(@rv, $1);
}
else {
push(@rv, $v);
}
}
}
else {
# Looking for regular name=value directives.
# Remove $SUFFIX variable seen on debian that is computed
# dynamically, but is usually empty.
foreach my $k (keys %def) {
$def{$k} =~ s/\$SUFFIX//g;
push(@rv, $k."=".$def{$k});
}
}
}
foreach my $md (split(/\t+/, $config{'defines_mods'})) {
# Add HAVE_ defines from modules
opendir(DIR, $md);
while(my $m = readdir(DIR)) {
if ($m =~ /^(mod_|lib)(.*).so$/i) {
push(@rv, "HAVE_".uc($2));
}
}
closedir(DIR);
}
foreach my $d (split(/\s+/, $config{'defines'})) {
push(@rv, $d);
}
@get_httpd_defines_cache = @rv;
return @rv;
}
# create_webfile_link(file)
# Creates a link in the debian-style link directory for a new website's file
sub create_webfile_link
{
local ($file) = @_;
if ($config{'link_dir'}) {
local $short = $file;
$short =~ s/^.*\///;
local $linksrc = "$config{'link_dir'}/$short";
&lock_file($linksrc);
symlink($file, $linksrc);
&unlock_file($linksrc);
}
}
# delete_webfile_link(file)
# If the given path is in a directory like /etc/apache2/sites-available, delete
# the link to it from /etc/apache2/sites-enabled
sub delete_webfile_link
{
local ($file) = @_;
if ($config{'link_dir'}) {
local $short = $file;
$short =~ s/^.*\///;
opendir(LINKDIR, $config{'link_dir'});
foreach my $f (readdir(LINKDIR)) {
if ($f ne "." && $f ne ".." &&
(&simplify_path(
&resolve_links($config{'link_dir'}."/".$f)) eq $file ||
$short eq $f)) {
&unlink_logged($config{'link_dir'}."/".$f);
}
}
closedir(LINKDIR);
}
}
# can_configure_apache_modules()
# Returns 1 if the distro has a way of selecting enabled Apache modules
sub can_configure_apache_modules
{
if ($gconfig{'os_type'} eq 'debian-linux') {
# Debian and Ubuntu use an /etc/apacheN/mods-enabled dir
return -d "$config{'httpd_dir'}/mods-enabled" &&
-d "$config{'httpd_dir'}/mods-available";
}
else {
return 0;
}
}
# list_configured_apache_modules()
# Returns a list of all Apache modules. Each is a hash containing a mod and
# enabled, disabled and available flags.
sub list_configured_apache_modules
{
if ($gconfig{'os_type'} eq 'debian-linux') {
# Find enabled modules
local @rv;
local $edir = "$config{'httpd_dir'}/mods-enabled";
opendir(EDIR, $edir);
foreach my $f (readdir(EDIR)) {
if ($f =~ /^(\S+)\.load$/) {
push(@rv, { 'mod' => $1, 'enabled' => 1 });
}
}
closedir(EDIR);
# Add available modules
local $adir = "$config{'httpd_dir'}/mods-available";
opendir(ADIR, $adir);
foreach my $f (readdir(ADIR)) {
if ($f =~ /^(\S+)\.load$/) {
local ($got) = grep { $_->{'mod'} eq $1 } @rv;
if (!$got) {
push(@rv, { 'mod' => $1, 'disabled' => 1 });
}
}
}
closedir(ADIR);
# XXX modules from apt-get
return sort { $a->{'mod'} cmp $b->{'mod'} } @rv;
}
else {
# Not supported
return ( );
}
}
# add_configured_apache_module(module)
# Updates the Apache configuration to use some module. Returns undef on success,
# or an error message on failure.
sub add_configured_apache_module
{
local ($mod) = @_;
if ($gconfig{'os_type'} eq 'debian-linux') {
# XXX download from apt-get ?
# Enable with a2enmod if installed
if (&has_command("a2enmod")) {
local $out = &backquote_logged(
"a2enmod ".quotemeta($mod)." 2>&1");
return $? ? $out : undef;
}
else {
# Fall back to creating links
local $adir = "$config{'httpd_dir'}/mods-available";
local $edir = "$config{'httpd_dir'}/mods-enabled";
opendir(ADIR, $adir);
foreach my $f (readdir(ADIR)) {
if ($f =~ /^\Q$mod->{'mod'}\E\./) {
&symlink_logged("$adir/$f", "$edir/$f") ||
return $!;
}
}
closedir(ADIR);
return undef;
}
}
else {
return "Operating system does not support Apache modules";
}
}
# remove_configured_apache_module(module)
# Updates the Apache configuration to stop using some module. Returns undef
# on success, or an error message on failure.
sub remove_configured_apache_module
{
local ($mod) = @_;
if ($gconfig{'os_type'} eq 'debian-linux') {
# Disable with a2dismod if installed
if (&has_command("a2dismod")) {
local $out = &backquote_logged(
"a2dismod ".quotemeta($mod)." 2>&1");
return $? ? $out : undef;
}
else {
# Fall back to removing links
local $edir = "$config{'httpd_dir'}/mods-enabled";
opendir(EDIR, $edir);
foreach my $f (readdir(EDIR)) {
if ($f =~ /^\Q$mod->{'mod'}\E\./) {
&unlink_logged("$edir/$f");
}
}
closedir(EDIR);
return undef;
}
}
else {
return "Operating system does not support Apache modules";
}
}
# is_virtualmin_domain(&virt)
# Returns the domain hash if some virtualhost is managed by Virtualmin
sub is_virtualmin_domain
{
local ($virt) = @_;
return 0 if ($config{'allow_virtualmin'});
local $n = &find_directive("ServerName", $virt->{'members'});
return undef if (!$n);
return undef if (!&foreign_check("virtual-server"));
&foreign_require("virtual-server");
local $d = &virtual_server::get_domain_by("dom", $n);
return $d if ($d);
$n =~ s/^www\.//i;
local $d = &virtual_server::get_domain_by("dom", $n);
return $d;
}
# update_last_config_change()
# Updates the flag file indicating when the config was changed
sub update_last_config_change
{
&open_tempfile(FLAG, ">$last_config_change_flag", 0, 1);
&close_tempfile(FLAG);
}
# restart_last_restart_time()
# Updates the flag file indicating when the config was changed
sub restart_last_restart_time
{
&open_tempfile(FLAG, ">$last_restart_time_flag", 0, 1);
&close_tempfile(FLAG);
}
# needs_config_restart()
# Returns 1 if a restart is needed for sure after a config change
sub needs_config_restart
{
my @cst = stat($last_config_change_flag);
my @rst = stat($last_restart_time_flag);
if (@cst && @rst && $cst[9] > $rst[9]) {
return 1;
}
return 0;
}
# format_config(conf-lines-ref, [indent])
# Formats Apache config lines with default
# four spaces of indent for each block
sub format_config
{
my ($conf_lref, $indent) = @_;
# Prevent formatting if not allowed in config
return if (!&format_config_allowed());
# Default single indent equals 4 spaces
$indent ||= 4;
$indent = " " x $indent;
# At first check if Apache blocks are ballanced
my $conf_block_opening;
my $conf_block_closing;
foreach my $l (@{$conf_lref}) {
# If line doesn't start with # disregard of trailing spaces
if ($l !~ /^\s*#/) {
# This is a new block, count it
if ($l =~ /(<[a-zA-Z]+).*>/) {
$conf_block_opening++;
}
# This is a new closing block, count it
if ($l =~ /(<\/[a-zA-Z]+).*>/) {
$conf_block_closing++;
}
}
}
# If the number of closing and opening blocks
# is the same then generate proper indents
if ($conf_block_opening == $conf_block_closing) {
my $conf_lvl = 0;
foreach my $l (@{$conf_lref}) {
my $indent_current = $indent x $conf_lvl;
# If line doesn't start with # disregard of trailing spaces
if ($l !~ /^\s*#/) {
# Indent up next line if a new block
if ($l =~ /(<[a-zA-Z]+).*>/) {
$conf_lvl++;
}
# Indent down next line if a closing block
if ($l =~ /(<\/[a-zA-Z]+).*>/) {
$conf_lvl--;
# Change current indent right now as it is a closing block
$indent_current = $indent x $conf_lvl;
}
}
# Replace beginning spaces with needed indent
$l =~ s/^\s*/$indent_current/
if($l);
}
}
}
# format_config(filename, [indent])
# Formats Apache config given file
sub format_config_file
{
my ($file, $indent) = @_;
# Prevent formatting if not allowed in config
return if (!&format_config_allowed());
# If file was deleted prevent recreating an empty file
return if (!-r $file);
# Lock file
&lock_file($file);
# Open file
my $conf_lref = &read_file_lines($file);
# Format
&format_config($conf_lref, $indent);
# Write file
&flush_file_lines($file);
# Unlock file
&unlock_file($file);
}
# format_modifed_configs([test-config])
# Formats all modifed Apache configs during the call
sub format_modifed_config_files
{
my ($force_config_test) = @_;
if($saved_conf_files) {
if (&format_config_allowed()) {
# Test config first if not already
# tested and don't format on error
if ($force_config_test) {
if ($config{'test_manual'} ||
$config{'test_always'}) {
my $conf_err = &test_config();
if ($conf_err) {
return;
}
}
}
# Format indents for each file individually
foreach my $saved_conf_file (&unique(@{$saved_conf_files})) {
&format_config_file($saved_conf_file, $config{'format_config_indent'});
}
}
}
}
# format_config_allowed()
# Checks if formatting config is allowed
sub format_config_allowed
{
return $config{'format_config'};
}
# clear_apache_modules_cache()
# If new Apache modules were enabled, force re-gen of the site file
# that contains the modules cache
sub clear_apache_modules_cache
{
&unlink_file($site_file);
&create_site_file();
&read_site_file();
}
1;