diff --git a/Check.pm b/Check.pm
new file mode 100644
index 0000000..45e7a8f
--- /dev/null
+++ b/Check.pm
@@ -0,0 +1,186 @@
+#============================================================= -*-perl-*-
+#
+# BackupPC::CGI::Check package
+#
+# DESCRIPTION
+#
+# This module implements the Check action for the CGI interface.
+#
+# AUTHOR
+# Heuze Florent
+#
+#========================================================================
+#
+# Released November 2019 - firewall-services.com
+#
+#========================================================================
+
+package BackupPC::CGI::Check;
+
+use strict;
+use lib "/usr/share/BackupPC/lib";
+use BackupPC::Lib;
+use BackupPC::CGI::Lib qw(:all);
+use Statistics::Descriptive;
+
+sub action
+{
+ # Init
+ my($str, $strGood, $header);
+ GetStatusInfo("hosts info");
+ my $Privileged = CheckPermission();
+ my $bpc = BackupPC::Lib->new();
+
+ # Start loop
+ foreach my $host ( GetUserHosts(1) ) {
+ my($incrAge, $reasonHilite, $frequency, $idBackup, $lastAge, $lastAgeColor, $tempState, $tempReason, $lastXferErrors, $lastXferErrorsColor, $ifErrors, $sizeConsistency, $sizeConsistencyColor);
+ my($shortErr);
+ my @Backups = $bpc->BackupInfoRead($host);
+
+ $bpc->ConfigRead($host);
+ %Conf = $bpc->Conf();
+
+ next if ( $Conf{XferMethod} eq "archive" );
+ next if ( !$Privileged && !CheckPermission($host) );
+
+ # Get frequency for this host
+ if ( $Conf{IncrPeriod} < $Conf{FullPeriod} ) {
+ $frequency = $Conf{IncrPeriod};
+ } else {
+ $frequency = $Conf{FullPeriod};
+ }
+
+ # ID
+ my $idBackup = $Backups[@Backups-1]->{num} if ( @Backups );
+
+ # Age
+ my $lastBackup = ( $Backups[-1]->{type} =~ m/^full|incr$/ ) ? -1 : -2;
+ $lastAge = sprintf("%.1f", (time - $Backups[$lastBackup]->{startTime}) / (24 * 3600));
+
+ # Color for age
+ if ( $lastAge < $frequency ) {
+ $lastAgeColor = "MediumSeaGreen";
+ } else {
+ $lastAgeColor = "Tomato";
+ }
+
+ # Color and link for errors
+ $lastXferErrors = $Backups[@Backups-1]->{xferErrs} if ( @Backups );
+ if ( $lastXferErrors == 0 ) {
+ $lastXferErrorsColor = "MediumSeaGreen";
+ $ifErrors = "";
+ } else {
+ $lastXferErrorsColor = "Tomato";
+ my $browseErrors = "?action=view&type=XferErr&num=$idBackup&host=$host";
+ $ifErrors = "| Read me !";
+ }
+
+ # Colors statuts
+ $reasonHilite = $Conf{CgiStatusHilightColor}{$Status{$host}{reason}} || $Conf{CgiStatusHilightColor}{$Status{$host}{state}};
+ $reasonHilite = " bgcolor=\"$reasonHilite\"" if ( $reasonHilite ne "" );
+
+ # Check Size Consistency
+ my $new_size = 0;
+ my $new_size_avg = 0;
+ my $new_size_q1 = 0;
+ my $new_size_q3 = 0;
+ my $sizes = new Statistics::Descriptive::Full;
+
+ foreach my $backup ( @Backups ) {
+ my $idBackup = $Backups[@Backups-1]->{num} if ( @Backups );
+ # Skip partial or active backups
+ next if ( $backup->{type} !~ m/^full|incr$/ );
+ # Push all the sizes in our data set to compute avg sizes
+ # Exclude backup N°0 as it'll always have much more new data than normal backups
+ $sizes->add_data($backup->{sizeNew}) unless ( $backup->{num} == 0 );
+
+ # Ignore the last backup if it's not full or incr (which means it's either partial or active)
+ my $i = ( $Backups[-1]->{type} =~ m/^full|incr$/ ) ? -1 : -2;
+ $new_size = $Backups[$i]->{sizeNew};
+ $new_size_avg = int $sizes->mean;
+ $new_size_q1 = eval { int $sizes->quantile(1) } || 0;
+ $new_size_q3 = eval { int $sizes->quantile(3) } || 0;
+ }
+
+ # Using a mathematical formula to calculate the consistency of the average size, for new files, on all backups
+ my $toobig = 0;
+ my $toosmall = 0;
+ my $sizeConsistencyColor = "Tomato";
+ my $sizeConsistency = "ANOMALOUS";
+
+ # TOO BIG ? If the size is 6 times higher than usual :
+ if ( $new_size > ($new_size_q3 + ($new_size_q3 - $new_size_q1) ) * 1.5 and $new_size > $new_size_avg * 6 ) {
+ $toobig = 1;
+ }
+
+ # TOO SMALL ? If the size is 3 times lower than usual :
+ if ( $new_size < ($new_size_q1 - ($new_size_q3 - $new_size_q1) ) * 1.5 and $new_size < $new_size_avg / 3 ) {
+ $toosmall = 1;
+ }
+
+ # Get result
+ if ( not $idBackup > 4) {
+ $sizeConsistencyColor = "Gray";
+ $sizeConsistency = "Not enough backups";
+ }
+ elsif ( not $toobig and not $toosmall and not $idBackup < 4) {
+ $sizeConsistencyColor = "MediumSeaGreen";
+ $sizeConsistency = "Normal";
+ }
+
+ # Get URL for explore file
+ my $browseFile = "?action=browse&host=$host";
+
+ # Show summary
+ $str .= <
+ $host ($idBackup) |
+ $lastAge (Freq: $frequency) |
+ $lastXferErrors $ifErrors |
+ $sizeConsistency |
+
+EOF
+
+ }
+ # End loop
+
+ # Time set
+ my $now = timeStamp2(time);
+ my $DUmaxTime = timeStamp2($Info{DUDailyMaxTime});
+ my $DUInodemaxTime = timeStamp2($Info{DUInodeDailyMaxTime});
+
+ # Show header
+ $header = <This check was generated at \$now.
+
+ File system pool size usage (\$DUmaxTime) :
+
+
+ File system inode size usage (\$DUInodemaxTime) :
+
+
\$Info{DUInodeDailyMax}%
+
+
+ \${h2("Backups summary")}
+
+
+EOF
+
+ # Show page
+ my $content = eval ("qq{$header}");
+ Header("BackupPC: Check", $content);
+ Trailer();
+}
+
+1;
diff --git a/README.md b/README.md
index 6d585a0..74c7c9e 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,21 @@
# BackupPC-Check
-VĂ©rification des sauvegardes BackupPC
\ No newline at end of file
+Verifying BackupPC Backups
+
+# Install
+
+## Install dependencies
+
+``yum -y perl-Statistics-Descriptive``
+
+## Install Backup-Check
+
+``cd /root ; git clone ssh://gitea@gitea.fws.fr:3222/fws/BackupPC-Check.git ; sh /root/BackupPC-Check/update.sh``
+
+## Add menu link
+
+Edit config -> CGI -> CgiNavBarLinks and add name "Check" with link "?action=check".
+
+# Update
+
+``sh /root/BackupPC-Check/update.sh``
diff --git a/update.sh b/update.sh
new file mode 100644
index 0000000..33d874e
--- /dev/null
+++ b/update.sh
@@ -0,0 +1,8 @@
+echo ""
+echo "Updating ..."
+echo ""
+git pull
+sleep 1
+\cp -v Check.pm /usr/share/BackupPC/lib/BackupPC/CGI/Check.pm
+echo ""
+echo "OK"