2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

98_backup: add support for FileLog path

git-svn-id: https://svn.fhem.de/fhem/trunk@19203 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
LeonGaultier 2019-04-17 08:30:37 +00:00
parent f3782ff972
commit a45a81bccd
2 changed files with 326 additions and 186 deletions

View File

@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
- feature: 98_backup: add support for FileLog path
- bugfix: 93_DbLog: fix problem with delta-h/delta-d MySQL if value will be
extracted by Regex Forum:#99280
- bugfix: 70_BOTVAC: fix missing battery parameters

View File

@ -1,9 +1,8 @@
################################################################
# $Id$
# vim: ts=2:et
# Developed with Kate
#
# (c) 2012 Copyright: Martin Fischer (m_fischer at gmx dot de)
# Maintained by Marko Oldenburg since 2019
# (c) 2012-2019 Copyright: Martin Fischer (m_fischer at gmx dot de)
# Rewrite and Maintained by Marko Oldenburg since 2019
# All rights reserved
#
# This script free software; you can redistribute it and/or modify
@ -21,91 +20,99 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# $Id$
#
################################################################
package main;
use strict;
use warnings;
use FHEM::Meta;
sub CommandBackup($$);
sub parseConfig($);
sub readModpath($$);
sub createArchiv($$$);
#####################################
sub backup_Initialize($$) {
my %hash = (
Fn => 'FHEM::backup::CommandBackup',
Hlp => ',create a backup of fhem configuration, state and modpath'
);
$cmds{backup} = \%hash;
return FHEM::Meta::InitMod( __FILE__, \%hash );
}
######################################
## unserer packagename
package FHEM::backup;
use strict;
use warnings;
use FHEM::Meta;
use GPUtils qw(GP_Import)
; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(AttrVal
InternalVal
gettimeofday
ResolveDateWildcards
attr
Log
fhemForked
defs
configDBUsed
TimeNow
BC_searchTelnet
BC_telnetDevice
DoTrigger
devspec2array
configDB)
);
}
my @pathname;
#####################################
sub
backup_Initialize($$)
{
my %hash = ( Fn => "CommandBackup",
Hlp => ",create a backup of fhem configuration, state and modpath" );
$cmds{backup} = \%hash;
}
sub CommandBackup($$) {
my ( $cl, $param ) = @_;
#####################################
sub
CommandBackup($$)
{
my ($cl, $param) = @_;
my $byUpdate = ($param && $param eq "startedByUpdate");
my $modpath = AttrVal("global", "modpath","");
my $configfile = AttrVal("global", "configfile", "");
my $statefile = AttrVal("global", "statefile", "");
my $byUpdate = ( $param && $param eq 'startedByUpdate' );
my $modpath = AttrVal( 'global', 'modpath', '.' );
my $configfile = AttrVal( 'global', 'configfile', $modpath . '/fhem.cfg' );
my $statefile = AttrVal( 'global', 'statefile', $modpath . '/log/fhem.save' );
my $dir = AttrVal( 'global', 'backupdir', $modpath . '/backup');
my $now = gettimeofday();
my @t = localtime($now);
$statefile = ResolveDateWildcards($statefile, @t);
$statefile = ResolveDateWildcards( $statefile, @t );
# prevent duplicate entries in backup list for default config, forum #54826
$configfile = '' if ($configfile eq 'fhem.cfg' || configDBUsed());
$statefile = '' if ($statefile eq "./log/fhem.save");
$configfile = '' if ( $configfile eq 'fhem.cfg' || configDBUsed() );
$statefile = '' if ( $statefile eq './log/fhem.save' );
my $msg;
my $ret;
Log 1, "NOTE: make sure you have a database backup!" if(configDBUsed());
my ($err,$backupdir) = createBackupDir( $dir, $modpath );
# set backupdir
my $backupdir;
if (!defined($attr{global}{backupdir})) {
$backupdir = "$modpath/backup";
} else {
if ($attr{global}{backupdir} =~ m/^\/.*/) {
$backupdir = $attr{global}{backupdir};
} elsif ($attr{global}{backupdir} =~ m/^\.+\/.*/) {
$backupdir = "$modpath/$attr{global}{backupdir}";
} else {
$backupdir = "$modpath/$attr{global}{backupdir}";
}
}
return Log( 1, 'ERROR: if create backup directory!' )
if ( defined($err) and $err );
# create backupdir if not exists
if (!-d $backupdir) {
Log 4, "backup create backupdir: '$backupdir'";
$ret = `(mkdir -p $backupdir) 2>&1`;
if ($ret) {
chomp $ret;
$msg = "backup: $ret";
return $msg;
}
}
Log( 1, 'NOTE: make sure you have a database backup!' )
if ( configDBUsed() );
$ret = addConfDBFiles( $configfile, $statefile );
$ret = readModpath( $modpath, $backupdir );
if(configDBUsed()) {
# add configDB configuration file
push @pathname, 'configDB.conf';
Log 4, "backup include: 'configDB.conf'";
} else {
# get pathnames to archiv
push @pathname, $configfile if($configfile);
Log 4, "backup include: '$configfile'";
$ret = parseConfig($configfile);
push @pathname, $statefile if($statefile);
Log 4, "backup include: '$statefile'";
}
$ret = readModpath($modpath,$backupdir);
## add all logfile path to pathname array
$ret = addLogPathToPathnameArray();
### remove double entries from pathname array
my %all=();
@all{@pathname}=1;
@pathname = keys %all;
# create archiv
$ret = createArchiv($backupdir, $cl, $byUpdate);
$ret = createArchiv( $backupdir, $cl, $byUpdate );
@pathname = [];
undef @pathname;
@ -113,68 +120,125 @@ CommandBackup($$)
return $ret;
}
sub
parseConfig($)
{
sub addConfDBFiles($$) {
my ($configfile,$statefile) = @_;
my $ret;
if ( configDBUsed() ) {
# add configDB configuration file
push( @pathname, 'configDB.conf' );
Log( 2, 'backup include: \'configDB.conf\'' );
## check if sqlite db file outside of modpath
if ( $configDB{type} eq 'SQLITE'
and defined($configDB{filename})
and $configDB{filename} !~ m#^[a-zA-Z].*|^\.\/[a-zA-Z].*# )
{
## backup sqlite db file
Log( 2, 'backup include SQLite DB File: ' . $configDB{filename} );
push( @pathname, $configDB{filename} );
}
}
else {
# get pathnames to archiv
push( @pathname, $configfile ) if ($configfile);
Log( 2, 'backup include: ' . $configfile );
$ret = parseConfig($configfile);
push( @pathname, $statefile ) if ($statefile);
Log( 2, 'backup include: ' . $statefile );
}
return $ret;
}
sub createBackupDir($$) {
my ($dir,$modpath) = @_;
my $msg;
my $ret;
my $backupdir = $dir =~ m#^\.(\/.*)$# ? $modpath.$1 : $dir =~ m#^\.\.\/# ? $modpath.'/'.$dir : $dir;
# create backupdir if not exists
if ( !-d $backupdir ) {
Log( 4, 'backup create backupdir: ' . $backupdir );
$ret = `(mkdir -p $backupdir) 2>&1`;
if ($ret) {
chomp($ret);
$msg = 'backup: ' . $ret;
return ($msg,undef);
}
}
return (undef,$backupdir);
}
sub parseConfig($);
sub parseConfig($) {
my $configfile = shift;
# we need default value to read included files
$configfile = $configfile ? $configfile : 'fhem.cfg';
my $fh;
my $msg;
my $ret;
if (!open($fh,$configfile)) {
$msg = "Can't open $configfile: $!";
Log 1, "backup $msg";
if ( !open( $fh, $configfile ) ) {
$msg = 'Can\'t open ' . $configfile . ': ' . $!;
Log( 1, 'backup ' . $msg );
return $msg;
}
while (my $l = <$fh>) {
while ( my $l = <$fh> ) {
$l =~ s/[\r\n]//g;
if ($l =~ m/^\s*include\s+(\S+)\s*.*$/) {
if (-e $1) {
if ( $l =~ m/^\s*include\s+(\S+)\s*.*$/ ) {
if ( -e $1 ) {
push @pathname, $1;
Log 4, "backup include: '$1'";
Log( 4, 'backup include: ' . $1 );
$ret = parseConfig($1);
} else {
Log 1, "backup configfile: '$1' does not exists! File not included."
}
else {
Log( 1,
'backup configfile: '
. $1
. ' does not exists! File not included.' );
}
}
}
close $fh;
return $ret;
}
sub
readModpath($$)
{
my ($modpath,$backupdir) = @_;
sub readModpath($$) {
my ( $modpath, $backupdir ) = @_;
my $msg;
my $ret;
if (!opendir(DH, $modpath)) {
$msg = "Can't open $modpath: $!";
Log 1, "backup $msg";
if ( !opendir( DH, $modpath ) ) {
$msg = 'Can\'t open $modpath: ' . $!;
Log( 1, 'backup ' . $msg );
return $msg;
}
my @files = <$modpath/*>;
foreach my $file (@files) {
if ($file eq $backupdir && (-d $file || -l $file)) {
Log 4, "backup exclude: '$file'";
} else {
Log 4, "backup include: '$file'";
if ( $file eq $backupdir && ( -d $file || -l $file ) ) {
Log( 4, 'backup exclude: ' . $file );
}
else {
Log( 4, 'backup include: ' . $file );
push @pathname, $file;
}
}
return $ret;
}
sub
createArchiv($$$)
{
my ($backupdir,$cl,$byUpdate) = @_;
my $backupcmd = (!defined($attr{global}{backupcmd}) ? undef : $attr{global}{backupcmd});
my $symlink = (!defined($attr{global}{backupsymlink}) ? "no" : $attr{global}{backupsymlink});
sub createArchiv($$$) {
my ( $backupdir, $cl, $byUpdate ) = @_;
my $backupcmd = AttrVal('global','backupcmd',undef);
my $symlink = AttrVal('global','backupsymlink','no');
my $tarOpts;
my $msg;
my $ret;
@ -183,48 +247,82 @@ createArchiv($$$)
$dateTime =~ s/ /_/g;
$dateTime =~ s/(:|-)//g;
my $pathlist = join( "\" \"", @pathname );
my $pathlist = join( '" "', @pathname );
my $cmd="";
if (!defined($backupcmd)) {
if (lc($symlink) eq "no") {
$tarOpts = "cf";
} else {
$tarOpts = "chf";
my $cmd = '';
if ( !defined($backupcmd) ) {
if ( lc($symlink) eq 'no' ) {
$tarOpts = 'czf';
}
else {
$tarOpts = 'chzf';
}
# prevents tar's output of "Removing leading /" and return total bytes of
# archive
$cmd = "tar -$tarOpts - \"$pathlist\" |gzip > $backupdir/FHEM-$dateTime.tar.gz";
} else {
$cmd = "$backupcmd \"$pathlist\"";
# prevents tar's output of "Removing leading /" and return total bytes of
# archive
# $cmd = "tar -$tarOpts - \"$pathlist\" |gzip > $backupdir/FHEM-$dateTime.tar.gz";
$cmd = "tar $tarOpts $backupdir/FHEM-$dateTime.tar.gz \"$pathlist\"";
}
Log 2, "Backup with command: $cmd";
if(!$fhemForked && !$byUpdate) {
else {
$cmd = $backupcmd . ' \"' . $pathlist . '\"';
}
Log( 2, 'Backup with command: ' . $cmd );
if ( !$fhemForked && !$byUpdate ) {
use Blocking;
our $BC_telnetDevice;
BC_searchTelnet("backup");
BC_searchTelnet('backup');
my $tp = $defs{$BC_telnetDevice}{PORT};
system("($cmd; echo Backup done;".
"$^X $0 localhost:$tp 'trigger global backup done')2>&1 &");
return "Started the backup in the background, watch the log for details";
system( "($cmd; echo Backup done;"
. "$^X $0 localhost:$tp 'trigger global backup done')2>&1 &" );
return
"Started the backup in the background, watch the log for details";
}
$ret = `($cmd) 2>&1`;
if($ret) {
if ($ret) {
chomp $ret;
Log 1, "backup $ret";
Log( 1, 'backup ' . $ret );
}
if (!defined($backupcmd) && -e "$backupdir/FHEM-$dateTime.tar.gz") {
if ( !defined($backupcmd) && -e "$backupdir/FHEM-$dateTime.tar.gz" ) {
my $size = -s "$backupdir/FHEM-$dateTime.tar.gz";
$msg = "backup done: FHEM-$dateTime.tar.gz ($size Bytes)";
DoTrigger("global", $msg);
Log 1, $msg;
$ret .= "\n".$msg;
DoTrigger( 'global', $msg );
Log( 1, $msg );
$ret .= "\n" . $msg;
}
return $ret;
}
sub addLogPathToPathnameArray() {
# my $modpath = shift;
my $ret;
my @logpathname;
my $extlogpath;
Log( 4, 'addLogPathToPathnameArray' );
foreach my $logFile (devspec2array('TYPE=FileLog')) {
Log( 5, 'found logFiles: ' . $logFile );
my $logpath = InternalVal($logFile,'currentlogfile','');
Log( 4, 'found logpath: ' . $logpath );
if ( $logpath =~ m#^(.+?)\/[\_|\-|\w]+\.log$# ) {
$extlogpath = $1;
Log( 4, 'found extlogpath: ' . $extlogpath );
if ( $1 =~ /^\/[A-Za-z]/ ) {
push( @logpathname, $extlogpath ) ;
Log( 4, 'external logpath include: ' . $extlogpath );
}
}
}
push( @pathname, @logpathname);
return $ret;
}
@ -260,6 +358,47 @@ createArchiv($$$)
<br>
</ul>
=end html
=for :application/json;q=META.json 98_backup.pm
{
"abstract": "Modul to retrieves apt information about Debian update state",
"x_lang": {
"de": {
"abstract": "Modul um apt Updateinformationen von Debian Systemen zu bekommen"
}
},
"keywords": [
"fhem-mod-device",
"fhem-core",
"backup",
"tar"
],
"release_status": "stable",
"license": "GPL_2",
"author": [
"Marko Oldenburg <leongaultier@gmail.com>"
],
"x_fhem_maintainer": [
"CoolTux"
],
"x_fhem_maintainer_github": [
"LeonGaultier"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM": 5.00918799,
"perl": 5.016,
"Meta": 0
},
"recommends": {
},
"suggests": {
}
}
}
}
=end :application/json;q=META.json
=cut