#! /usr/bin/perl

use DBI;
use Getopt::Long qw(:config no_ignore_case bundling);
use strict;
use Cwd qw(abs_path);
use JSON::MaybeXS qw(encode_json decode_json);
use Data::Dumper;
require "/usr/local/bin/backupCred.pm";

our $NAS_ROOT;
my $BAK_ROOT="/backupdisk";

my $bakSourceUUID=`findmnt $NAS_ROOT -no UUID`;
my $bakSourceDir="";
my $bakDuration;
my $bakResult;
my $bakTargetUUID=`findmnt $BAK_ROOT -no UUID`;
$bakTargetUUID =~ s/\s+$//;
$bakSourceUUID =~ s/\s+$//;
#print "bakTarget default:$bakTargetUUID:\n";
our $database;
our $dbusername;
our $dbpassword;

my $vendor;
my $model;
my $serial;
my $fsuuid;
my $fslabel;
my $fstype;
my $fssize;
my $fspath;
my $fsmount;
my $fssizegb;

my $all;
my $dev;	# command line option for device
binmode(STDOUT,":utf8");
GetOptions(
	"all|a" => \$all,
	"dev|d=s" => \$dev
	) or die "Error in command line options";

if ($all && $dev ne "") {
	die "--dev and --all must not be specified both!";
}

my $dbh=DBI -> connect("dbi:Pg:host=localhost;dbname=$database",$dbusername,$dbpassword,
	{AutoCommit => 0, RaiseError => 1})
	or die "cannot connect to database $DBI::errstr\n";

if ($all) {
	updateDisk("");
} elsif ($dev ne "") {
	updateDisk($dev);
} else {
	if ((!$bakSourceUUID) || (!$bakTargetUUID)) {
		print "Nas ($NAS_ROOT) and Backup ($BAK_ROOT) must be mounted! Stop.\n";
		$dbh->disconnect;
		exit;
	}
	chdir("/dev/disk/by-uuid");	# else abs_path will not work
	my $p=readlink "/dev/disk/by-uuid/$bakTargetUUID";
	$p=abs_path($p);
	chop($p);	# remove the partition number to get the root device
	updateDisk($p);
}
$dbh->disconnect;
exit;

# updates all partitions on a given disk (e.g. 'sda')
# if disk is empty, all partitions of every disk are updated
sub updateDisk
{
	my $disk=$_[0];
	my $blockdevs=decode_json(`lsblk -Jbo UUID,LABEL,FSSIZE,VENDOR,MODEL,SERIAL,PATH,MOUNTPOINT,TYPE $disk`);
	for my $blockdev (@{$blockdevs->{blockdevices}}) {
		if ($blockdev->{type} eq "disk") {
			updateOneDisk($blockdev->{path});
		}
	}
}

# updates all partitions on one disk
# must be called with the devicename (e.g. '/dev/sda')
sub updateOneDisk
{
	my $blockdev=$_[0];
	my $blockdevs=decode_json(`lsblk -Jbo UUID,LABEL,FSSIZE,VENDOR,MODEL,SERIAL,PATH,MOUNTPOINT,TYPE $blockdev`);
	# first, find the disk to get vendor, serial etc.
	# this is not always the first entry, so we have to scan for it
	for my $dev (@{$blockdevs->{blockdevices}}) {
	if ($dev->{type} eq "disk") {
			$vendor=$dev->{'vendor'};
			$model=$dev->{'model'};
			$serial=$dev->{'serial'};
		}
	}
	# then find everything else
	for my $dev (@{$blockdevs->{blockdevices}}) {
	if ($dev->{type} ne "disk" && $dev->{fssize}>0) {
			$fsuuid=$dev->{'uuid'};
			$fslabel=$dev->{'label'};
			$fspath=$dev->{'path'};
			$fsmount=$dev->{'mountpoint'};
			$fstype=$dev->{'type'};
			$fssize=$dev->{'fssize'};
			$fssizegb=int($fssize/1024/1024/1024);
#			print "part:$vendor:$model:$serial fs:$fsuuid:$fslabel:$fssizegb:$fsmount\n";
			my $sth=$dbh->prepare(<<SQL);
			SELECT "mediaUUID", "mediaName", "mediaSizeGB" FROM "tMedia" WHERE "mediaUUID"='$dev->{'uuid'}'
SQL
			my $rv=$sth->execute();
			my @row=$sth->fetchrow_array();
			$sth->finish();

			if (!@row[0]) {
				print "Inserting media information for $fsuuid ($fslabel)\n";
				$sth=$dbh->prepare(<<SQL);
				INSERT INTO "tMedia" ("mediaUUID", "mediaName", "mediaSizeGB", "mediaSerNo", "mediaVendor", "mediaModel", "mediaPath", "mediaMountpoint", "mediaType")
				VALUES ('$fsuuid', '$fslabel', $fssizegb, '$serial', '$vendor', '$model', '$fspath', '$fsmount', '$fstype')
SQL
				my $rv=$sth->execute();
				$dbh->commit();
			} else {
				print "Updating media information for  $fsuuid ($fslabel)\n";
				$sth=$dbh->prepare(<<SQL);
				UPDATE "tMedia" set "mediaName"='$fslabel', "mediaSizeGB"=$fssizegb, "mediaSerNo"='$serial', "mediaVendor"='$vendor', "mediaModel"='$model', "mediaPath"='$fspath', "mediaMountpoint"='$fsmount', "mediaType"='$fstype' WHERE "mediaUUID"='$fsuuid'
SQL
				my $rv=$sth->execute();
				$dbh->commit();
			}
		}
	}
	print "\n";
}
