HEX
Server: Apache
System: Linux vps-cdc32557.vps.ovh.ca 5.15.0-156-generic #166-Ubuntu SMP Sat Aug 9 00:02:46 UTC 2025 x86_64
User: hanode (1017)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //usr/share/webmin/virtual-server/backuplog.cgi
#!/usr/bin/perl
# Show logs of backups this user has permissions on

require './virtual-server-lib.pl';
&ReadParse();
&can_backup_log() || &error($text{'backuplg_ecannot'});

# Get days to show logs for
$days = $in{'sched'} ? 365 : ($config{'backuplog_days'} || 7);

# Get all logs
@logs = &list_backup_logs($in{'search'} ? undef : time()-24*60*60*$days);

# Get backups function for listing depending on plugin
my $plugin = $in{'plugin'};
($plugin) = $in{'search'} =~ /plugin:(\S+)/ if (!$plugin && $in{'search'});
if (@logs) {
	if ($plugin) {
		@logs = grep { $_->{'plugged'} eq $plugin } @logs;
		}
	else {
		@logs = grep { !$_->{'plugged'} } @logs;
		}
	}

$anylogs = scalar(@logs);
@logs = grep { &can_backup_log($_) } @logs;

if ($plugin && &plugin_defined($plugin, 'feature_backup_safe')) {
	# Plugin specific header
	%ptext = &load_language($plugin);
	&ui_print_header(undef, $ptext{'feat_backuplog_title'}, "",
		'backup_logs', undef, 1);
	}
else {
	# Default header
	$plugin = undef;
	&ui_print_header(undef, $text{'backuplog_title'}, "", 'backup_logs');
	}

if (!@logs) {
	# None found
	print $in{'search'} ? $text{'backuplog_nomatch'} :
		   $anylogs ? $text{'backuplog_none2'} :
			      $text{'backuplog_none'},"\n";
	goto print_footer;
	}

# Show search form
if ($in{'search'}) {
	my $search = $in{'search'} // '';
	my %by = (
		schedule  => sub { ($_[0]{'sched'}        // '') =~ /$_[1]/i },
		user      => sub { ($_[0]{'user'}         // '') =~ /$_[1]/i },
		domain    => sub { ($_[0]{'doms'}         // '') =~ /$_[1]/i },
		dest      => sub { ($_[0]{'dest'}         // '') =~ /$_[1]/i },
		desc      => sub { ($_[0]{'desc'}         // '') =~ /$_[1]/i },
		time => sub { (&make_date($_[0]{'start'}) // '') =~ /$_[1]/i },
		type => sub {
			my $label = $_[0]{increment}
				? $text{"viewbackup_inc1"}
				: $text{"viewbackup_inc0"};
			return $label =~ /$_[1]/i;
		},
		size => sub {
			my ($log) = @_;
			my $sz = $log->{size} // 0;
			my @conds;
			# Parse one or few comparisons: >10M or <1G >512K
			while ($_[1] =~ /([<>]=?)\s*([0-9]+(?:\.[0-9]+)?)\s*([kmg])?b?/ig) {
				my ($op, $num, $u) = ($1, $2+0, lc($3 // ''));
				my $mult = $u eq 'k' ? 1024
					: $u eq 'm' ? 1024*1024
					: $u eq 'g' ? 1024*1024*1024
					: 1;
				push @conds, [$op, $num * $mult];
				}
			
			return 1 unless (@conds);
			
			foreach my $c (@conds) {
				my ($op, $bytes) = @$c;
				return 0 if ($op eq '>'  && !($sz >  $bytes));
				return 0 if ($op eq '>=' && !($sz >= $bytes));
				return 0 if ($op eq '<'  && !($sz <  $bytes));
				return 0 if ($op eq '<=' && !($sz <= $bytes));
				}
			return 1;
			},
		status => sub {
			my $ok   = $_[0]{'ok'} // 0;
			my $errs = $_[0]{'errdoms'};
			my $key  = $ok ? ($errs ? 'partial' : 'ok') : 'failed';
			my $txt  = $ok
				? ($errs
					? $text{'backuplog_status_partial'}
					: $text{'backuplog_status_ok'})
				: $text{'backuplog_status_failed'};
			lc($_[1]) eq $key || $txt =~ /\Q$_[1]\E/i;
			},
		plugin => sub { ($_[0]{'plugged'}  // '') =~ /$_[1]/i },
	);

	if ($search =~ /[a-z_]+\s*[:=]/i) {
		# Support multi field terms search separated by commas
		my @terms = grep length, map { s/^\s+|\s+$//gr }
					 split /,/, $search;

		# Build anded filters
		my @filters;
		foreach my $t (@terms) {
			next unless $t =~ /\A([a-z_]+)\s*[:=]\s*(.+)\z/i;
			my ($k, $v) = (lc $1, $2);
			push @filters, sub {
				my ($log) = @_;
				$by{$k} ? $by{$k}->($log, $v) : 0
				};
			}
		if (@filters) {
			@logs = grep {
					my $log = $_;
					my $ok = 1;
					for my $f (@filters) {
						$ok &&= $f->($log);
						last unless ($ok);
						}
					$ok;
				} @logs;
			}
		}
	else {
		@logs = grep { $_->{'user'} eq $in{'search'} ||
			       $_->{'doms'} =~ /\Q$in{'search'}\E/i ||
			       $_->{'dest'} =~ /\Q$in{'search'}\E/i } @logs;

		}
	}
elsif ($in{'sched'}) {
	($sched) = grep { $_->{'id'} eq $in{'sched'} }
			&list_scheduled_backups();
	unless ($sched) {
		print &ui_alert_box($text{'backuplg_esched'}, 'danger',
			undef, undef, '');
		goto print_footer;
		}
	@logs = grep { $_->{'sched'} eq $in{'sched'} } @logs;
	}
else {
	$placeholder = &text('backuplog_days', $days);
	}

# Tell the user what he is searching for
if ($in{'search'}) {
	my $msg;
	if (!@logs) {
		$msg =  &text('backuplog_nomatch',
			      "<tt>".&html_escape($in{'search'})."</tt>");
		print &ui_alert_box($msg, 'warn', undef, undef, '');
		}
	else {
		$placeholder = &text('backuplog_match',
			     &html_escape($in{'search'}));
		}
	}
elsif ($in{'sched'}) {
	my $msg;
	if ($sched->{desc}) {
		$msg = &text('backuplog_scheddesc', $sched->{'desc'});
		}
	else {
		@dests = &get_scheduled_backup_dests($sched);
		@nices = map { &nice_backup_url($_, 1) } @dests;
		$msg = &text('backuplog_sched', "<tt>$nices[0]</tt>");
		}
		
	print &ui_alert_box($msg, 'info', undef, undef, '');
	}

print &ui_form_start("backuplog.cgi");
print "$text{'backuplog_search'}&nbsp;\n";
my $search = $in{'search'} || '';
$search =~ s/(,?plugin:[^,]+)//g;
print &ui_textbox("search", $search, 40, undef, undef,
		  "placeholder='$placeholder'");
print &ui_hidden("plugin", $plugin) if ($plugin);
print &ui_hidden("return", $in{'return'});
print &ui_submit($text{'ui_searchok'});
print &ui_form_end(),"<p>\n";

if (@logs) {
	# Show in a table
	@table = ( );
	$hasdesc = 0;
	foreach $log (@logs) {
		$hasdesc++ if ($log->{'desc'});
		}
	foreach $log (sort { $b->{'start'} <=> $a->{'start'} } @logs) {
		@dnames = &backup_log_own_domains($log);
		next if (!@dnames);
		$ddesc = scalar(@dnames) == 0 ?
				$text{'backuplog_nodoms'} :
			 scalar(@dnames) <= 2 ?
				join(", ", @dnames) :
				&text('backuplog_doms', scalar(@dnames));
		my $link = &make_link('view_backuplog.cgi',
				      ['id', $log->{'id'}], 'search', 'plugin',
				      'return');
		push(@table, [
			"<a href='$link'>".
			 &nice_backup_url($log->{'dest'}, 1, 1)."</a>",
			$ddesc,
			$hasdesc ? ( &html_escape($log->{'desc'}) ) : ( ),
		        $log->{'user'} || "<i>root</i>",
			&make_date($log->{'start'}),
			&short_nice_hour_mins_secs(
				$log->{'end'} - $log->{'start'}),
			$log->{'increment'} == 1 ? $text{'viewbackup_inc1'} :
						   $text{'viewbackup_inc0'},
			&nice_size($log->{'size'}),
			$log->{'ok'} && !$log->{'errdoms'} ? $text{'backuplog_status_ok'} :
			 $log->{'ok'} && $log->{'errdoms'} ?
			  &ui_text_color($text{'backuplog_status_partial'}, 'warn') :
			  &ui_text_color($text{'backuplog_status_failed'}, 'danger')
			]);
		}
	print &ui_columns_table([ $text{'sched_dest'}, $text{'sched_doms'},
				  $hasdesc ? ( $text{'backuplog_desc'} ) : ( ),
				  $text{'backuplog_who'},
				  $text{'backuplog_when'},
				  $text{'backuplog_len'},
				  $text{'backuplog_incr'},
				  $text{'backuplog_size'},
				  $text{'backuplog_status'} ],
				100, \@table);
				  
	}

print_footer:
&ui_print_footer($in{'return'}, $ptext{'index_return'}) if ($plugin);