From b0a134e779c605b38cf19e9e894728f7758e8e76 Mon Sep 17 00:00:00 2001 From: Marko Oldenburg Date: Thu, 28 Mar 2019 15:12:11 +0100 Subject: [PATCH] rewrite modul and add extra logDir backup --- 98_backup.pm | 442 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 261 insertions(+), 181 deletions(-) diff --git a/98_backup.pm b/98_backup.pm index b8beb17..e3b3ccb 100644 --- a/98_backup.pm +++ b/98_backup.pm @@ -1,8 +1,7 @@ ################################################################ -# $Id: 98_backup.pm 18643 2019-02-19 14:33:01Z CoolTux $ -# vim: ts=2:et +# Developed with Kate # -# (c) 2012 Copyright: Martin Fischer (m_fischer at gmx dot de) +# (c) 2012-2019 Copyright: Martin Fischer (m_fischer at gmx dot de) # Maintained by Marko Oldenburg since 2019 # All rights reserved # @@ -21,211 +20,251 @@ # 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 + gettimeofday + ResolveDateWildcards + attr + Log + fhemForked + defs + configDBUsed + TimeNow + BC_searchTelnet + BC_telnetDevice + DoTrigger) + ); +} 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) = @_; + + my $byUpdate = ($param && $param eq 'startedByUpdate'); + my $modpath = AttrVal('global', 'modpath', ''); + my $configfile = AttrVal('global', 'configfile', ''); + my $statefile = AttrVal('global', 'statefile', ''); + my $logDir = AttrVal('global', 'logdir', 'none'); + my $now = gettimeofday(); + my @t = localtime($now); + $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'); + my $msg; + my $ret; + + Log(1, 'NOTE: make sure you have a database backup!') if(configDBUsed()); + + # 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}; + } + } + + # 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; + } + } + + 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 extra logdir path to backup + push(@pathname, $logDir) if($logDir ne 'none'); + + # create archiv + $ret = createArchiv($backupdir, $cl, $byUpdate); + + @pathname = []; + undef @pathname; + + return $ret; } -##################################### -sub -CommandBackup($$) -{ - my ($cl, $param) = @_; +sub parseConfig($); - my $byUpdate = ($param && $param eq "startedByUpdate"); - my $modpath = AttrVal("global", "modpath",""); - my $configfile = AttrVal("global", "configfile", ""); - my $statefile = AttrVal("global", "statefile", ""); - my $now = gettimeofday(); - my @t = localtime($now); - $statefile = ResolveDateWildcards($statefile, @t); +sub parseConfig($) { + my $configfile = shift; + # we need default value to read included files + $configfile = $configfile ? $configfile : 'fhem.cfg'; + my $fh; + my $msg; + my $ret; - # 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"); - my $msg; - my $ret; - - Log 1, "NOTE: make sure you have a database backup!" if(configDBUsed()); - - # 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}"; + if (!open($fh,$configfile)) { + $msg = 'Can\'t open ' . $configfile . ': ' . $!; + Log(1, 'backup ' . $msg); + return $msg; } - } - # 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; + while (my $l = <$fh>) { + $l =~ s/[\r\n]//g; + if ($l =~ m/^\s*include\s+(\S+)\s*.*$/) { + if (-e $1) { + push @pathname, $1; + Log(4, 'backup include: ' . $1); + $ret = parseConfig($1); + } + else { + Log(1, 'backup configfile: ' . $1 . ' does not exists! File not included.'); + } + } } - } - - 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); - - # create archiv - $ret = createArchiv($backupdir, $cl, $byUpdate); - - @pathname = []; - undef @pathname; - - return $ret; + + close $fh; + return $ret; } -sub -parseConfig($) -{ - my $configfile = shift; - # we need default value to read included files - $configfile = $configfile ? $configfile : 'fhem.cfg'; - my $fh; - my $msg; - my $ret; +sub readModpath($$) { + my ($modpath,$backupdir) = @_; + my $msg; + my $ret; - if (!open($fh,$configfile)) { - $msg = "Can't open $configfile: $!"; - Log 1, "backup $msg"; - return $msg; - } - - while (my $l = <$fh>) { - $l =~ s/[\r\n]//g; - if ($l =~ m/^\s*include\s+(\S+)\s*.*$/) { - if (-e $1) { - push @pathname, $1; - Log 4, "backup include: '$1'"; - $ret = parseConfig($1); - } else { - Log 1, "backup configfile: '$1' does not exists! File not included." - } + if (!opendir(DH, $modpath)) { + $msg = 'Can\'t open $modpath: ' . $!; + Log(1, 'backup ' . $msg); + return $msg; } - } - close $fh; - return $ret; + + 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); + push @pathname, $file; + } + } + + return $ret; } -sub -readModpath($$) -{ - my ($modpath,$backupdir) = @_; - my $msg; - my $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}); + my $tarOpts; + my $msg; + my $ret; - 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'"; - push @pathname, $file; + my $dateTime = TimeNow(); + $dateTime =~ s/ /_/g; + $dateTime =~ s/(:|-)//g; + + my $pathlist = join( '" "', @pathname ); + + my $cmd=''; + if (!defined($backupcmd)) { + if (lc($symlink) eq 'no') { + $tarOpts = 'cf'; + } + else { + $tarOpts = 'chf'; + } + + # 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\""; } - } - return $ret; -} + else { + $cmd = $backupcmd . ' \"' . $pathlist . '\"'; + } + + Log(2, 'Backup with command: ' . $cmd); + if(!$fhemForked && !$byUpdate) { + use Blocking; + our $BC_telnetDevice; + BC_searchTelnet('backup'); + my $tp = $defs{$BC_telnetDevice}{PORT}; -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}); - my $tarOpts; - my $msg; - my $ret; + 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`; - my $dateTime = TimeNow(); - $dateTime =~ s/ /_/g; - $dateTime =~ s/(:|-)//g; - - my $pathlist = join( "\" \"", @pathname ); - - my $cmd=""; - if (!defined($backupcmd)) { - if (lc($symlink) eq "no") { - $tarOpts = "cf"; - } else { - $tarOpts = "chf"; + if($ret) { + chomp $ret; + Log(1, 'backup ' . $ret); + } + + 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; } - # 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\""; - - } - Log 2, "Backup with command: $cmd"; - if(!$fhemForked && !$byUpdate) { - use Blocking; - our $BC_telnetDevice; - 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"; - } - $ret = `($cmd) 2>&1`; - - if($ret) { - chomp $ret; - Log 1, "backup $ret"; - } - 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; - } - return $ret; + return $ret; } 1; @@ -260,6 +299,47 @@ createArchiv($$$)
- =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 " + ], + "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