first commit
This commit is contained in:
commit
3ac7e48592
265
98_backup.pm
Normal file
265
98_backup.pm
Normal file
@ -0,0 +1,265 @@
|
||||
################################################################
|
||||
# $Id: 98_backup.pm 18643 2019-02-19 14:33:01Z CoolTux $
|
||||
# vim: ts=2:et
|
||||
#
|
||||
# (c) 2012 Copyright: Martin Fischer (m_fischer at gmx dot de)
|
||||
# Maintained by Marko Oldenburg since 2019
|
||||
# All rights reserved
|
||||
#
|
||||
# This script free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# The GNU General Public License can be found at
|
||||
# http://www.gnu.org/copyleft/gpl.html.
|
||||
# A copy is found in the textfile GPL.txt and important notices to the license
|
||||
# from the author is found in LICENSE.txt distributed with these scripts.
|
||||
#
|
||||
# This script is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
################################################################
|
||||
|
||||
package main;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub CommandBackup($$);
|
||||
sub parseConfig($);
|
||||
sub readModpath($$);
|
||||
sub createArchiv($$$);
|
||||
|
||||
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 $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);
|
||||
|
||||
# create archiv
|
||||
$ret = createArchiv($backupdir, $cl, $byUpdate);
|
||||
|
||||
@pathname = [];
|
||||
undef @pathname;
|
||||
|
||||
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;
|
||||
|
||||
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."
|
||||
}
|
||||
}
|
||||
}
|
||||
close $fh;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub
|
||||
readModpath($$)
|
||||
{
|
||||
my ($modpath,$backupdir) = @_;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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});
|
||||
my $tarOpts;
|
||||
my $msg;
|
||||
my $ret;
|
||||
|
||||
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";
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
=item command
|
||||
=item summary create a backup of the FHEM installation
|
||||
=item summary_DE erzeugt eine Sicherungsdatei der FHEM Installation
|
||||
=begin html
|
||||
|
||||
<a name="backup"></a>
|
||||
<h3>backup</h3>
|
||||
<ul>
|
||||
<code>backup</code><br>
|
||||
<br>
|
||||
The complete FHEM directory (containing the modules), the WebInterface
|
||||
pgm2 (if installed) and the config-file will be saved into a .tar.gz
|
||||
file by default. The file is stored with a timestamp in the
|
||||
<a href="#modpath">modpath</a>/backup directory or to a directory
|
||||
specified by the global attribute <a href="#backupdir">backupdir</a>.<br>
|
||||
Note: tar and gzip must be installed to use this feature.
|
||||
<br>
|
||||
<br>
|
||||
If you need to call tar with support for symlinks, you could set the
|
||||
global attribute <a href="#backupsymlink">backupsymlink</a> to everything
|
||||
else as "no".
|
||||
<br>
|
||||
<br>
|
||||
You could pass the backup to your own command / script by using the
|
||||
global attribute <a href="#backupcmd">backupcmd</a>.
|
||||
<br>
|
||||
<br>
|
||||
</ul>
|
||||
|
||||
|
||||
=end html
|
||||
=cut
|
Loading…
x
Reference in New Issue
Block a user