use strict;
use List::Util qw(any);
+use URI;
# enable only the following on debugging purpose
#use warnings;
my %pakfiresettings = ();
my %mainsettings = ();
+# The page mode is used to explictly switch between user interface functions:
+my $PM_DEFAULT = 'default'; # Default user interface with command processing
+my $PM_LOGREAD = 'logread'; # Log messages viewer (ignores all commands)
+my $pagemode = $PM_DEFAULT;
+
+# Get Pakfire status
+my %pakfire_status = &Pakfire::status();
+
# Load general settings
&General::readhash("${General::swroot}/main/settings", \%mainsettings);
+&General::readhash("${General::swroot}/pakfire/settings", \%pakfiresettings);
&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
-# Get CGI request data
+# Get CGI POST request data
$cgiparams{'ACTION'} = '';
-$cgiparams{'VALID'} = '';
+$cgiparams{'FORCE'} = '';
$cgiparams{'INSPAKS'} = '';
$cgiparams{'DELPAKS'} = '';
&Header::getcgihash(\%cgiparams);
+# Get CGI GET request data (if available)
+if($ENV{'QUERY_STRING'}) {
+ my $uri = URI->new($ENV{'REQUEST_URI'});
+ my %query = $uri->query_form;
+
+ my $mode = lc($query{'mode'} // '');
+ if(($mode eq $PM_DEFAULT) || ($mode eq $PM_LOGREAD)) {
+ $pagemode = $mode; # Limit to existing modes
+ }
+}
+
### Process AJAX/JSON request ###
if($cgiparams{'ACTION'} eq 'json-getstatus') {
# Send HTTP headers
# Read /var/log/messages backwards until a "Pakfire started" header is found,
# to capture all messages of the last (i.e. current) Pakfire run
- my @messages = `tac /var/log/messages | sed -n '/pakfire:/{p;/Pakfire.*started/q}'`;
+ my @messages = `tac /var/log/messages 2>/dev/null | sed -n '/pakfire:/{p;/Pakfire.*started/q}'`;
# Test if the log contains an error message (fastest implementation, stops at first match)
my $failure = any{ index($_, 'ERROR') != -1 } @messages;
my %status = (
'running' => &_is_pakfire_busy() || "0",
'running_since' => &General::age("$Pakfire::lockfile") || "0s",
- 'reboot' => (-e "/var/run/need_reboot") || "0",
+ 'reboot' => ("$pakfire_status{'RebootRequired'}" eq "yes") || "0",
'failure' => $failure || "0"
);
exit;
}
+### Process Pakfire install/update commands ###
+if(($cgiparams{'ACTION'} ne '') && ($pagemode eq $PM_DEFAULT)) {
+ if(&_is_pakfire_busy()) {
+ $errormessage = $Lang::tr{'pakfire already busy'};
+ $pagemode = $PM_LOGREAD; # Running Pakfire instance found, switch to log viewer mode
+ } elsif(($cgiparams{'ACTION'} eq 'install') && ($cgiparams{'FORCE'} eq 'on')) {
+ my @pkgs = split(/\|/, $cgiparams{'INSPAKS'});
+ &General::system_background("/usr/local/bin/pakfire", "install", "--non-interactive", "--no-colors", @pkgs);
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif(($cgiparams{'ACTION'} eq 'remove') && ($cgiparams{'FORCE'} eq 'on')) {
+ my @pkgs = split(/\|/, $cgiparams{'DELPAKS'});
+ &General::system_background("/usr/local/bin/pakfire", "remove", "--non-interactive", "--no-colors", @pkgs);
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif($cgiparams{'ACTION'} eq 'update') {
+ &General::system_background("/usr/local/bin/pakfire", "update", "--force", "--no-colors");
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif($cgiparams{'ACTION'} eq 'upgrade') {
+ &General::system_background("/usr/local/bin/pakfire", "upgrade", "-y", "--no-colors");
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ } elsif($cgiparams{'ACTION'} eq $Lang::tr{'save'}) {
+ $pakfiresettings{"TREE"} = $cgiparams{"TREE"};
+
+ # Check for valid input
+ if ($pakfiresettings{"TREE"} !~ m/^(stable|testing|unstable)$/) {
+ $errormessage .= $Lang::tr{'pakfire invalid tree'};
+ }
+
+ unless ($errormessage) {
+ &General::writehash("${General::swroot}/pakfire/settings", \%pakfiresettings);
+
+ # Update lists
+ &General::system_background("/usr/local/bin/pakfire", "update", "--force", "--no-colors");
+ &_http_pagemode_redirect($PM_LOGREAD, 1);
+ }
+ }
+}
+
### Start pakfire page ###
&Header::showhttpheaders();
&Header::openpage($Lang::tr{'pakfire configuration'}, 1, $extraHead);
&Header::openbigbox('100%', 'left', '', $errormessage);
-# Process Pakfire commands
-if (($cgiparams{'ACTION'} eq 'install') && (! &_is_pakfire_busy())) {
- my @pkgs = split(/\|/, $cgiparams{'INSPAKS'});
- if ("$cgiparams{'FORCE'}" eq "on") {
- &General::system_background("/usr/local/bin/pakfire", "install", "--non-interactive", "--no-colors", @pkgs);
- } else {
- &Header::openbox("100%", "center", $Lang::tr{'request'});
- my @output = &General::system_output("/usr/local/bin/pakfire", "resolvedeps", "--no-colors", @pkgs);
- print <<END;
- <table><tr><td colspan='2'>$Lang::tr{'pakfire install package'} @pkgs $Lang::tr{'pakfire possible dependency'}
- <pre>
-END
- foreach (@output) {
- $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
- print "$_\n";
- }
- print <<END;
- </pre></td></tr>
- <tr><td colspan='2'>$Lang::tr{'pakfire accept all'}</td></tr>
- <tr><td colspan='2'> </td></tr>
- <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='INSPAKS' value='$cgiparams{'INSPAKS'}' />
- <input type='hidden' name='FORCE' value='on' />
- <input type='hidden' name='ACTION' value='install' />
- <input type='image' alt='$Lang::tr{'install'}' title='$Lang::tr{'install'}' src='/images/go-next.png' />
- </form>
- </td>
- <td align='left'>
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='ACTION' value='' />
- <input type='image' alt='$Lang::tr{'abort'}' title='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
- </form>
- </td>
- </tr>
- </table>
-END
- &Header::closebox();
- &Header::closebigbox();
- &Header::closepage();
- exit;
- }
-} elsif (($cgiparams{'ACTION'} eq 'remove') && (! &_is_pakfire_busy())) {
- my @pkgs = split(/\|/, $cgiparams{'DELPAKS'});
- if ("$cgiparams{'FORCE'}" eq "on") {
- &General::system_background("/usr/local/bin/pakfire", "remove", "--non-interactive", "--no-colors", @pkgs);
- } else {
- &Header::openbox("100%", "center", $Lang::tr{'request'});
- my @output = &General::system_output("/usr/local/bin/pakfire", "resolvedeps", "--no-colors", @pkgs);
- print <<END;
- <table><tr><td colspan='2'>$Lang::tr{'pakfire uninstall package'} @pkgs $Lang::tr{'pakfire possible dependency'}
- <pre>
-END
- foreach (@output) {
- $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
- print "$_\n";
- }
- print <<END;
- </pre></td></tr>
- <tr><td colspan='2'>$Lang::tr{'pakfire uninstall all'}</td></tr>
- <tr><td colspan='2'> </td></tr>
- <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='DELPAKS' value='$cgiparams{'DELPAKS'}' />
- <input type='hidden' name='FORCE' value='on' />
- <input type='hidden' name='ACTION' value='remove' />
- <input type='image' alt='$Lang::tr{'uninstall'}' title='$Lang::tr{'uninstall'}' src='/images/go-next.png' />
- </form>
- </td>
- <td align='left'>
- <form method='post' action='$ENV{'SCRIPT_NAME'}'>
- <input type='hidden' name='ACTION' value='' />
- <input type='image' alt='$Lang::tr{'abort'}' title='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
- </form>
- </td>
- </tr>
- </table>
-END
- &Header::closebox();
- &Header::closebigbox();
- &Header::closepage();
- exit;
- }
-
-} elsif (($cgiparams{'ACTION'} eq 'update') && (! &_is_pakfire_busy())) {
- &General::system_background("/usr/local/bin/pakfire", "update", "--force", "--no-colors");
-} elsif (($cgiparams{'ACTION'} eq 'upgrade') && (! &_is_pakfire_busy())) {
- &General::system_background("/usr/local/bin/pakfire", "upgrade", "-y", "--no-colors");
-} elsif ($cgiparams{'ACTION'} eq "$Lang::tr{'save'}") {
- $pakfiresettings{"TREE"} = $cgiparams{"TREE"};
-
- # Check for valid input
- if ($pakfiresettings{"TREE"} !~ m/^(stable|testing|unstable)$/) {
- $errormessage .= $Lang::tr{'pakfire invalid tree'};
- }
-
- unless ($errormessage) {
- &General::writehash("${General::swroot}/pakfire/settings", \%pakfiresettings);
-
- # Update lists
- &General::system_background("/usr/local/bin/pakfire", "update", "--force", "--no-colors");
- }
-}
-
-&General::readhash("${General::swroot}/pakfire/settings", \%pakfiresettings);
-
-my %selected=();
-my %checked=();
-
-$selected{"TREE"} = ();
-$selected{"TREE"}{"stable"} = "";
-$selected{"TREE"}{"testing"} = "";
-$selected{"TREE"}{"unstable"} = "";
-$selected{"TREE"}{$pakfiresettings{"TREE"}} = "selected";
-
-# DPC move error message to top so it is seen!
+# Show error message
if ($errormessage) {
&Header::openbox('100%', 'left', $Lang::tr{'error messages'});
print "<font class='base'>$errormessage </font>\n";
&Header::closebox();
}
-# Show log output while Pakfire is running
-if(&_is_pakfire_busy()) {
+# Show only log output while Pakfire is running and stop afterwards
+if(($pagemode eq $PM_LOGREAD) || (&_is_pakfire_busy())) {
&Header::openbox("100%", "center", "Pakfire");
print <<END
exit;
}
-my $core_release = `cat /opt/pakfire/db/core/mine 2>/dev/null`;
-chomp($core_release);
-my $core_update_age = &General::age("/opt/pakfire/db/core/mine");
-my $corelist_update_age = &General::age("/opt/pakfire/db/lists/core-list.db");
-my $server_update_age = &General::age("/opt/pakfire/db/lists/server-list.db");
-my $packages_update_age = &General::age("/opt/pakfire/db/lists/packages_list.db");
+# Show Pakfire install/remove dependencies and confirm form
+# (_is_pakfire_busy status was checked before and can be omitted)
+if (($cgiparams{'ACTION'} eq 'install') && ($pagemode eq $PM_DEFAULT)) {
+ &Header::openbox("100%", "center", $Lang::tr{'request'});
+
+ my @pkgs = split(/\|/, $cgiparams{'INSPAKS'});
+ my @output = &General::system_output("/usr/local/bin/pakfire", "resolvedeps", "--no-colors", @pkgs);
+ print <<END;
+ <table style="width: 100%"><tr><td colspan='2'><p>$Lang::tr{'pakfire install package'} <strong>@{pkgs}</strong><br>
+ $Lang::tr{'pakfire possible dependency'}</p>
+ <pre>
+END
+ foreach (@output) {
+ $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
+ print "$_\n";
+ }
+ print <<END;
+ </pre></td></tr>
+ <tr><td colspan='2'>$Lang::tr{'pakfire accept all'}</td></tr>
+ <tr><td colspan='2'> </td></tr>
+ <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='INSPAKS' value='$cgiparams{'INSPAKS'}' />
+ <input type='hidden' name='FORCE' value='on' />
+ <input type='hidden' name='ACTION' value='install' />
+ <input type='image' alt='$Lang::tr{'install'}' title='$Lang::tr{'install'}' src='/images/go-next.png' />
+ </form>
+ </td>
+ <td align='left'>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='ACTION' value='' />
+ <input type='image' alt='$Lang::tr{'abort'}' title='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
+ </form>
+ </td>
+ </tr>
+ </table>
+END
+ &Header::closebox();
+ &Header::closebigbox();
+ &Header::closepage();
+ exit;
+
+} elsif (($cgiparams{'ACTION'} eq 'remove') && ($pagemode eq $PM_DEFAULT)) {
+ &Header::openbox("100%", "center", $Lang::tr{'request'});
+
+ my @pkgs = split(/\|/, $cgiparams{'DELPAKS'});
+ my @output = &General::system_output("/usr/local/bin/pakfire", "resolvedeps", "--no-colors", @pkgs);
+ print <<END;
+ <table style="width: 100%"><tr><td colspan='2'><p>$Lang::tr{'pakfire uninstall package'} <strong>@{pkgs}</strong><br>
+ $Lang::tr{'pakfire possible dependency'}</p>
+ <pre>
+END
+ foreach (@output) {
+ $_ =~ s/\\e\[[0-1]\;[0-9]+m//g;
+ print "$_\n";
+ }
+ print <<END;
+ </pre></td></tr>
+ <tr><td colspan='2'>$Lang::tr{'pakfire uninstall all'}</td></tr>
+ <tr><td colspan='2'> </td></tr>
+ <tr><td align='right'><form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='DELPAKS' value='$cgiparams{'DELPAKS'}' />
+ <input type='hidden' name='FORCE' value='on' />
+ <input type='hidden' name='ACTION' value='remove' />
+ <input type='image' alt='$Lang::tr{'uninstall'}' title='$Lang::tr{'uninstall'}' src='/images/go-next.png' />
+ </form>
+ </td>
+ <td align='left'>
+ <form method='post' action='$ENV{'SCRIPT_NAME'}'>
+ <input type='hidden' name='ACTION' value='' />
+ <input type='image' alt='$Lang::tr{'abort'}' title='$Lang::tr{'abort'}' src='/images/dialog-error.png' />
+ </form>
+ </td>
+ </tr>
+ </table>
+END
+ &Header::closebox();
+ &Header::closebigbox();
+ &Header::closepage();
+ exit;
+}
+
+# Show Pakfire main page
+my %selected=();
+my %checked=();
+
+$selected{"TREE"} = ();
+$selected{"TREE"}{"stable"} = "";
+$selected{"TREE"}{"testing"} = "";
+$selected{"TREE"}{"unstable"} = "";
+$selected{"TREE"}{$pakfiresettings{"TREE"}} = "selected";
&Header::openbox("100%", "center", "Pakfire");
print <<END;
<table id="pfmain">
END
-if ( -e "/var/run/need_reboot") {
+if ("$pakfire_status{'RebootRequired'}" eq "yes") {
print "\t\t<tr><td colspan='2'><a href='/cgi-bin/shutdown.cgi'>$Lang::tr{'needreboot'}!</a></td></tr>\n";
}
+
print <<END;
<tr><td class="heading">$Lang::tr{'pakfire system state'}:</td>
<td class="heading">$Lang::tr{'available updates'}:</td></tr>
- <tr><td><strong>$Lang::tr{'pakfire core update level'}: $core_release</strong>
+ <tr><td><strong>$Lang::tr{'pakfire core update level'}: $pakfire_status{'Release'}</strong>
<hr>
<div class="pflist">
- $Lang::tr{'pakfire last update'} $core_update_age $Lang::tr{'pakfire ago'}<br>
- $Lang::tr{'pakfire last serverlist update'} $server_update_age $Lang::tr{'pakfire ago'}<br>
- $Lang::tr{'pakfire last core list update'} $corelist_update_age $Lang::tr{'pakfire ago'}<br>
- $Lang::tr{'pakfire last package update'} $packages_update_age $Lang::tr{'pakfire ago'}
+ $Lang::tr{'pakfire last update'} $pakfire_status{'LastUpdate'} $Lang::tr{'pakfire ago'}<br>
+ $Lang::tr{'pakfire last serverlist update'} $pakfire_status{'LastServerListUpdate'} $Lang::tr{'pakfire ago'}<br>
+ $Lang::tr{'pakfire last core list update'} $pakfire_status{'LastCoreListUpdate'} $Lang::tr{'pakfire ago'}<br>
+ $Lang::tr{'pakfire last package update'} $pakfire_status{'LastPakListUpdate'} $Lang::tr{'pakfire ago'}
</div>
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
<input type='hidden' name='ACTION' value='update' />
<select name="UPDPAKS" class="pflist" size="5" disabled>
END
- &Pakfire::dblist("upgrade", "forweb");
+ if ("$pakfire_status{'CoreUpdateAvailable'}" eq "yes") {
+ print "<option value=\"core\">$Lang::tr{'core update'} -- $pakfire_status{'CoreVersion'} -- $Lang::tr{'release'}: $pakfire_status{'Release'} -> $pakfire_status{'AvailableRelease'}</option>\n";
+ }
+
+ if ($pakfire_status{'PakUpdatesAvailable'} > 0) {
+ my %upgradelist = &Pakfire::dblist("upgrade");
+ foreach my $pak (sort keys %upgradelist) {
+ print "<option value=\"$pak\">$Lang::tr{'pak update'}: $pak -- $Lang::tr{'version'}: $upgradelist{$pak}{'ProgVersion'} -> $upgradelist{$pak}{'AvailableProgVersion'} -- $Lang::tr{'release'}: $upgradelist{$pak}{'Release'} -> $upgradelist{$pak}{'AvailableRelease'}</option>\n";
+ }
+ }
+
print <<END;
</select>
<input type='hidden' name='ACTION' value='upgrade' />
<select name="INSPAKS" class="pflist" size="10" multiple>
END
- &Pakfire::dblist("notinstalled", "forweb");
+ my %notinstalledlist = &Pakfire::dblist("notinstalled");
+ foreach my $pak (sort keys %notinstalledlist) {
+ print "<option value=\"$pak\">$pak-$notinstalledlist{$pak}{'ProgVersion'}-$notinstalledlist{$pak}{'Release'}</option>\n";
+ }
+
print <<END;
</select>
<input type='hidden' name='ACTION' value='install' />
<select name="DELPAKS" class="pflist" size="10" multiple>
END
- &Pakfire::dblist("installed", "forweb");
+ my %installedlist = &Pakfire::dblist("installed");
+ foreach my $pak (sort keys %installedlist) {
+ print "<option value=\"$pak\">$pak-$installedlist{$pak}{'ProgVersion'}-$installedlist{$pak}{'Release'}</option>\n";
+ }
+
print <<END;
</select>
<input type='hidden' name='ACTION' value='remove' />
print "Content-Type: application/json\n";
print "\n"; # End of HTTP headers
}
+
+# Send HTTP 303 redirect headers to change page mode
+# GET is always used to display the redirected page, which will remove already processed POST form data.
+# Note: Custom headers must be sent before the HTML output is started by &Header::showhttpheaders().
+# If switch_mode is set to true, the global page mode variable ("$pagemode") is also updated immediately.
+sub _http_pagemode_redirect {
+ my ($mode, $switch_mode) = @_;
+ $mode //= $PM_DEFAULT;
+ $switch_mode //= 0;
+
+ # Send HTTP redirect with GET parameter
+ my $location = "https://$ENV{'SERVER_NAME'}:$ENV{'SERVER_PORT'}$ENV{'SCRIPT_NAME'}?mode=${mode}";
+ print "Status: 303 See Other\n";
+ print "Location: $location\n";
+
+ # Change global page mode
+ if($switch_mode) {
+ $pagemode = $mode;
+ }
+}