2019-09-24 00:54:27 +08:00
#!@PERL_EXECUTABLE@ -wT
2013-03-17 07:45:21 +08:00
#
# ==========================================================================
#
# ZoneMinder Update Script, $Date$, $Revision$
# Copyright (C) 2001-2008 Philip Coombes
#
# This program is 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.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
2016-12-26 23:23:16 +08:00
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2013-03-17 07:45:21 +08:00
#
# ==========================================================================
2015-03-30 23:47:16 +08:00
= head1 NAME
2016-01-23 02:12:39 +08:00
zmupdate . pl - check and upgrade ZoneMinder database
2015-03-30 23:47:16 +08:00
= head1 SYNOPSIS
2021-08-06 01:27:04 +08:00
zmupdate . pl - c , - - check | - f , - - freshen | - v <version> , - - version = <version> [ - u <dbuser> - p <dbpass> ]
2015-03-30 23:47:16 +08:00
= head1 DESCRIPTION
This script just checks what the most recent release of ZoneMinder is
at the the moment . It will eventually be responsible for applying and
configuring upgrades etc , including on the fly upgrades .
= head1 OPTIONS
2017-05-17 23:40:54 +08:00
- c , - - check - Check for updated versions of ZoneMinder
- f , - - freshen - Freshen the configuration in the database . Equivalent of old zmconfig . pl - noi
- - migrate - events - Update database structures as per USE_DEEP_STORAGE setting .
2021-04-19 23:56:59 +08:00
- v <version> , - - version = <version> - Force upgrade to the current version from <version>
- u <dbuser> , - - user = <dbuser> - Alternate DB user with privileges to alter DB
- p <dbpass> , - - pass = <dbpass> - Password of alternate DB user with privileges to alter DB
2021-04-28 22:03:26 +08:00
- s , - - super - Use system maintenance account on debian based systems instead of unprivileged account
2021-04-19 23:56:59 +08:00
- d <dir> , - - dir = <dir> - Directory containing update files if not in default build location
2017-05-17 23:40:54 +08:00
- interactive - interact with the user
- nointeractive - do not interact with the user
2015-03-30 23:47:16 +08:00
= cut
2013-03-17 07:45:21 +08:00
use strict ;
use bytes ;
2015-10-04 21:10:05 +08:00
use version ;
2019-05-16 21:37:11 +08:00
use Crypt::Eksblowfish::Bcrypt ;
2019-05-14 02:29:24 +08:00
use Data::Entropy::Algorithms qw( rand_bits ) ;
2013-03-17 07:45:21 +08:00
# ==========================================================================
#
# These are the elements you can edit to suit your installation
#
# ==========================================================================
use constant CHECK_INTERVAL = > ( 1 * 24 * 60 * 60 ) ; # Interval between version checks
# ==========================================================================
#
# Don't change anything below here
#
# ==========================================================================
@ EXTRA_PERL_LIB @
2016-05-20 20:53:53 +08:00
use ZoneMinder::Base qw( :all ) ;
use ZoneMinder::Config qw( :all ) ;
use ZoneMinder::Logger qw( :all ) ;
use ZoneMinder::General qw( :all ) ;
use ZoneMinder::Database qw( :all ) ;
2013-03-17 07:45:21 +08:00
use POSIX ;
use DBI ;
use Getopt::Long ;
2015-03-30 23:47:16 +08:00
use autouse 'Pod::Usage' = > qw( pod2usage ) ;
2015-04-16 13:42:56 +08:00
use autouse 'Data::Dumper' = > qw( Dumper ) ;
2013-03-17 07:45:21 +08:00
2013-12-17 05:32:02 +08:00
use constant EVENT_PATH = > ( $ Config { ZM_DIR_EVENTS } =~ m | /|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/ ' . $ Config { ZM_DIR_EVENTS } ) ;
2013-03-17 07:45:21 +08:00
$| = 1 ;
$ ENV { PATH } = '/bin:/usr/bin:/usr/local/bin' ;
$ ENV { SHELL } = '/bin/sh' if exists $ ENV { SHELL } ;
delete @ ENV { qw( IFS CDPATH ENV BASH_ENV ) } ;
2013-12-17 05:32:02 +08:00
my $ web_uid = ( getpwnam ( $ Config { ZM_WEB_USER } ) ) [ 2 ] ;
2013-03-17 07:45:21 +08:00
my $ use_log = ( ( $> == 0 ) || ( $> == $ web_uid ) ) ;
logInit ( toFile = > $ use_log ? DEBUG:NOLOG ) ;
logSetSignal ( ) ;
my $ interactive = 1 ;
my $ check = 0 ;
my $ freshen = 0 ;
my $ rename = 0 ;
my $ zoneFix = 0 ;
my $ migrateEvents = 0 ;
my $ version = '' ;
2013-12-17 05:32:02 +08:00
my $ dbUser = $ Config { ZM_DB_USER } ;
my $ dbPass = $ Config { ZM_DB_PASS } ;
2021-04-28 22:03:26 +08:00
my $ super = 0 ;
2013-03-17 07:45:21 +08:00
my $ updateDir = '' ;
2015-03-30 23:47:16 +08:00
GetOptions (
'check' = > \ $ check ,
'freshen' = > \ $ freshen ,
'rename' = > \ $ rename ,
'zone-fix' = > \ $ zoneFix ,
'migrate-events' = > \ $ migrateEvents ,
'version=s' = > \ $ version ,
'interactive!' = > \ $ interactive ,
'user:s' = > \ $ dbUser ,
'pass:s' = > \ $ dbPass ,
2021-04-28 22:03:26 +08:00
'super' = > \ $ super ,
2015-03-30 23:47:16 +08:00
'dir:s' = > \ $ updateDir
2017-05-17 23:40:54 +08:00
) or pod2usage ( - exitstatus = > - 1 ) ;
2013-03-17 07:45:21 +08:00
2017-01-15 23:54:23 +08:00
my $ dbh = zmDbConnect ( undef , { mysql_multi_statements = > 1 } ) ;
2020-06-07 23:57:20 +08:00
if ( ! $ dbh ) {
die "Unable to connect to db\n" ;
}
2013-12-17 05:32:02 +08:00
$ Config { ZM_DB_USER } = $ dbUser ;
$ Config { ZM_DB_PASS } = $ dbPass ;
2020-06-04 03:36:47 +08:00
# we escape dbpass with single quotes so that $ in the password has no effect, but dbpass could have a ' in it.
$ dbPass =~ s/'/\\'/g ;
2013-08-19 23:19:34 +08:00
2017-05-17 23:40:54 +08:00
if ( ! ( $ check || $ freshen || $ rename || $ zoneFix || $ migrateEvents || $ version ) ) {
if ( $ Config { ZM_DYN_DB_VERSION } ) {
$ version = $ Config { ZM_DYN_DB_VERSION } ;
} else {
2020-06-10 01:19:19 +08:00
print ( STDERR "Please give a valid option\n" ) ;
2015-03-30 23:47:16 +08:00
pod2usage ( - exitstatus = > - 1 ) ;
2017-05-17 23:40:54 +08:00
}
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
if ( ( $ check + $ freshen + $ rename + $ zoneFix + $ migrateEvents + ( $ version ? 1 : 0 ) ) > 1 ) {
2020-06-10 01:19:19 +08:00
print ( STDERR "Please give only one option\n" ) ;
2017-05-17 23:40:54 +08:00
pod2usage ( - exitstatus = > - 1 ) ;
}
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
if ( $ check && $ Config { ZM_CHECK_FOR_UPDATES } ) {
2020-06-10 01:19:19 +08:00
print ( 'Update agent starting at ' . strftime ( '%y/%m/%d %H:%M:%S' , localtime ( ) ) . "\n" ) ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
my $ currVersion = $ Config { ZM_DYN_CURR_VERSION } ;
my $ lastVersion = $ Config { ZM_DYN_LAST_VERSION } ;
my $ lastCheck = $ Config { ZM_DYN_LAST_CHECK } ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
if ( ! $ currVersion ) {
$ currVersion = $ Config { ZM_VERSION } ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
my $ sql = "update Config set Value = ? where Name = 'ZM_DYN_CURR_VERSION'" ;
2020-06-10 01:19:19 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( $ currVersion ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
$ sth - > finish ( ) ;
}
2020-06-10 01:19:19 +08:00
while ( 1 ) {
2017-05-17 23:40:54 +08:00
my $ now = time ( ) ;
if ( ! $ lastVersion || ! $ lastCheck || ( ( $ now - $ lastCheck ) > CHECK_INTERVAL ) ) {
2020-06-10 01:19:19 +08:00
Info ( 'Checking for updates' ) ;
2017-05-17 23:40:54 +08:00
use LWP::UserAgent ;
my $ ua = LWP::UserAgent - > new ;
2020-06-10 01:19:19 +08:00
$ ua - > agent ( 'ZoneMinder Update Agent/' . ZM_VERSION ) ;
2017-05-17 23:40:54 +08:00
if ( $ Config { ZM_UPDATE_CHECK_PROXY } ) {
2020-06-10 01:19:19 +08:00
$ ua - > proxy ( 'http' , $ Config { ZM_UPDATE_CHECK_PROXY } ) ;
2017-05-17 23:40:54 +08:00
}
2020-06-10 01:19:19 +08:00
my $ req = HTTP::Request - > new ( GET = > 'https://update.zoneminder.com/version.txt' ) ;
2017-05-17 23:40:54 +08:00
my $ res = $ ua - > request ( $ req ) ;
if ( $ res - > is_success ) {
$ lastVersion = $ res - > content ;
chomp ( $ lastVersion ) ;
$ lastCheck = $ now ;
2020-06-10 01:19:19 +08:00
Info ( 'Got version: ' . $ lastVersion ) ;
2017-05-17 23:40:54 +08:00
2020-06-10 01:19:19 +08:00
my $ lv_sql = 'UPDATE Config SET Value = ? WHERE Name = \'ZM_DYN_LAST_VERSION\'' ;
my $ lv_sth = $ dbh - > prepare_cached ( $ lv_sql ) or die ( "Can't prepare '$lv_sql': " . $ dbh - > errstr ( ) ) ;
my $ lv_res = $ lv_sth - > execute ( $ lastVersion ) or die ( "Can't execute: " . $ lv_sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
$ lv_sth - > finish ( ) ;
2020-06-10 01:19:19 +08:00
my $ lc_sql = 'UPDATE Config SET Value = ? WHERE Name = \'ZM_DYN_LAST_CHECK\'' ;
my $ lc_sth = $ dbh - > prepare_cached ( $ lc_sql ) or die ( "Can't prepare '$lc_sql': " . $ dbh - > errstr ( ) ) ;
my $ lc_res = $ lc_sth - > execute ( $ lastCheck ) or die ( "Can't execute: " . $ lc_sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
$ lc_sth - > finish ( ) ;
} else {
2020-06-10 01:19:19 +08:00
Error ( 'Error check failed: \'' . $ res - > status_line ( ) . '\'' ) ;
2017-05-17 23:40:54 +08:00
}
}
2020-06-10 01:19:19 +08:00
sleep ( 3600 ) ;
2017-05-17 23:40:54 +08:00
}
2020-06-10 01:19:19 +08:00
print ( 'Update agent exiting at ' . strftime ( '%y/%m/%d %H:%M:%S' , localtime ( ) ) . "\n" ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
if ( $ rename ) {
require File::Find ;
2013-03-17 07:45:21 +08:00
2020-06-10 01:19:19 +08:00
chdir ( EVENT_PATH ) ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
sub renameImage {
my $ file = $ _ ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
# Ignore directories
if ( - d $ file ) {
2020-06-10 01:19:19 +08:00
print ( "Checking directory '$file'\n" ) ;
2017-05-17 23:40:54 +08:00
return ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
if ( $ file !~ /(capture|analyse)-(\d+)(\.jpg)/ ) {
return ;
2013-03-17 07:45:21 +08:00
}
2020-06-10 01:19:19 +08:00
my $ newFile = $ 2 . '-' . $ 1 . $ 3 ;
2013-03-17 07:45:21 +08:00
2020-06-10 01:19:19 +08:00
print ( "Renaming '$file' to '$newFile'\n" ) ;
rename ( $ file , $ newFile ) or warn ( "Can't rename '$file' to '$newFile'" ) ;
2017-05-17 23:40:54 +08:00
}
2020-06-10 01:19:19 +08:00
File::Find:: find ( \ & renameImage , '.' ) ;
} # end if rename
2017-05-17 23:40:54 +08:00
2020-06-10 01:19:19 +08:00
if ( $ zoneFix ) {
my $ sql = "SELECT Z.*, M.Width AS MonitorWidth, M.Height AS MonitorHeight FROM Zones AS Z INNER JOIN Monitors AS M ON Z.MonitorId = M.Id WHERE Z.Units = 'Percent'" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
my @ zones ;
2020-06-10 01:19:19 +08:00
while ( my $ zone = $ sth - > fetchrow_hashref ( ) ) {
push ( @ zones , $ zone ) ;
2017-05-17 23:40:54 +08:00
}
$ sth - > finish ( ) ;
2020-06-10 01:19:19 +08:00
$ sql = 'UPDATE Zones SET MinAlarmPixels = ?, MaxAlarmPixels = ?, MinFilterPixels = ?, MaxFilterPixels = ?, MinBlobPixels = ?, MaxBlobPixels = ? WHERE Id = ?' ;
$ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
foreach my $ zone ( @ zones ) {
my $ zone_width = ( ( $ zone - > { HiX } * $ zone - > { MonitorWidth } ) - ( $ zone - > { LoX } * $ zone - > { MonitorWidth } ) ) / 100 ;
my $ zone_height = ( ( $ zone - > { HiY } * $ zone - > { MonitorHeight } ) - ( $ zone - > { LoY } * $ zone - > { MonitorHeight } ) ) / 100 ;
my $ zone_area = $ zone_width * $ zone_height ;
my $ monitor_area = $ zone - > { MonitorWidth } * $ zone - > { MonitorHeight } ;
my $ res = $ sth - > execute (
( $ zone - > { MinAlarmPixels } * $ monitor_area ) / $ zone_area ,
( $ zone - > { MaxAlarmPixels } * $ monitor_area ) / $ zone_area ,
( $ zone - > { MinFilterPixels } * $ monitor_area ) / $ zone_area ,
( $ zone - > { MaxFilterPixels } * $ monitor_area ) / $ zone_area ,
( $ zone - > { MinBlobPixels } * $ monitor_area ) / $ zone_area ,
( $ zone - > { MaxBlobPixels } * $ monitor_area ) / $ zone_area ,
$ zone - > { Id }
2020-06-10 01:19:19 +08:00
) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
}
$ sth - > finish ( ) ;
2020-06-10 01:19:19 +08:00
} # end if zoneFix
2017-05-17 23:40:54 +08:00
if ( $ migrateEvents ) {
2020-06-10 01:19:19 +08:00
my $ webUid = ( getpwnam ( $ Config { ZM_WEB_USER } ) ) [ 2 ] ;
my $ webGid = ( getgrnam ( $ Config { ZM_WEB_USER } ) ) [ 2 ] ;
2017-05-17 23:40:54 +08:00
if ( ! ( ( $> == 0 ) || ( $> == $ webUid ) ) ) {
2020-06-10 01:19:19 +08:00
print ( "Error, migrating events can only be done as user root or " . $ Config { ZM_WEB_USER } . ".\n" ) ;
exit ( - 1 ) ;
2017-05-17 23:40:54 +08:00
}
# Run as web user/group
$( = $ webGid ;
2020-06-10 01:19:19 +08:00
$ ) = $ webGid ;
2017-05-17 23:40:54 +08:00
$< = $ webUid ;
$> = $ webUid ;
2020-06-10 01:19:19 +08:00
print ( '
About to convert saved events to deep storage , please ensure that ZoneMinder is fully stopped before proceeding .
This process is not easily reversible . Are you sure you wish to proceed ?
Press \ 'y\' to continue or \'n\' to abort : ' ) ;
2017-05-17 23:40:54 +08:00
my $ response = <STDIN> ;
2020-06-10 01:19:19 +08:00
chomp ( $ response ) ;
2017-05-17 23:40:54 +08:00
while ( $ response !~ /^[yYnN]$/ ) {
2020-06-10 01:19:19 +08:00
print ( "Please press 'y' to continue or 'n' to abort only : " ) ;
2017-05-17 23:40:54 +08:00
$ response = <STDIN> ;
2020-06-10 01:19:19 +08:00
chomp ( $ response ) ;
2017-05-17 23:40:54 +08:00
}
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
if ( $ response =~ /^[yY]$/ ) {
2020-06-10 01:19:19 +08:00
print ( "Converting all events to deep storage.\n" ) ;
2013-03-17 07:45:21 +08:00
2020-06-10 01:19:19 +08:00
chdir ( $ Config { ZM_PATH_WEB } ) ;
my $ sql = 'SELECT *, unix_timestamp(StartTime) AS UnixStartTime FROM Events' ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or Fatal ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
my $ res = $ sth - > execute ( ) ;
if ( ! $ res ) {
2020-06-10 01:19:19 +08:00
Fatal ( "Can't fetch Events: " . $ sth - > errstr ( ) ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
while ( my $ event = $ sth - > fetchrow_hashref ( ) ) {
my $ oldEventPath = $ Config { ZM_DIR_EVENTS } . '/' . $ event - > { MonitorId } . '/' . $ event - > { Id } ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
if ( ! - d $ oldEventPath ) {
2020-06-10 01:19:19 +08:00
print ( "Warning, can't find old event path '$oldEventPath', already converted?\n" ) ;
2017-05-17 23:40:54 +08:00
next ;
}
2013-03-17 07:45:21 +08:00
2020-06-10 01:19:19 +08:00
print ( 'Converting event ' . $ event - > { Id } . "\n" ) ;
my $ newDatePath = $ Config { ZM_DIR_EVENTS } . '/' . $ event - > { MonitorId } . '/' . strftime ( '%y/%m/%d' , localtime ( $ event - > { UnixStartTime } ) ) ;
my $ newTimePath = strftime ( '%H/%M/%S' , localtime ( $ event - > { UnixStartTime } ) ) ;
2017-05-17 23:40:54 +08:00
my $ newEventPath = $ newDatePath . '/' . $ newTimePath ;
( my $ truncEventPath = $ newEventPath ) =~ s | / \ d + $| | ;
2020-06-10 01:19:19 +08:00
makePath ( $ truncEventPath , $ Config { ZM_PATH_WEB } ) ;
2017-05-17 23:40:54 +08:00
my $ idLink = $ newDatePath . '/.' . $ event - > { Id } ;
2020-06-10 01:19:19 +08:00
symlink ( $ newTimePath , $ idLink ) or die ( "Can't symlink $newTimePath -> $idLink: $!" ) ;
rename ( $ oldEventPath , $ newEventPath ) or die ( "Can't move $oldEventPath -> $newEventPath: $!" ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
$ sth - > finish ( ) ;
2020-06-10 01:19:19 +08:00
print ( "Updating configuration.\n" ) ;
2019-08-26 00:30:06 +08:00
$ sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_USE_DEEP_STORAGE'" ;
2020-06-10 01:19:19 +08:00
$ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
$ res = $ sth - > execute ( 1 ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
$ sth - > finish ( ) ;
2020-06-10 01:19:19 +08:00
print ( "All events converted.\n\n" ) ;
2017-05-17 23:40:54 +08:00
} else {
2020-06-10 01:19:19 +08:00
print ( "Aborting event conversion.\n\n" ) ;
2017-05-17 23:40:54 +08:00
}
2013-03-17 07:45:21 +08:00
}
2020-06-10 01:19:19 +08:00
2017-05-17 23:40:54 +08:00
if ( $ freshen ) {
2020-06-10 01:19:19 +08:00
print ( "\nFreshening configuration in database\n" ) ;
2017-06-13 09:39:37 +08:00
migratePaths ( ) ;
2019-05-13 22:31:09 +08:00
migratePasswords ( ) ;
2017-05-17 23:40:54 +08:00
ZoneMinder::Config:: loadConfigFromDB ( ) ;
ZoneMinder::Config:: saveConfigToDB ( ) ;
2013-03-17 07:45:21 +08:00
}
2013-11-13 22:42:10 +08:00
2013-12-07 02:47:39 +08:00
# Don't do innoDB upgrade if not interactive
if ( $ interactive ) {
2017-05-17 23:40:54 +08:00
# Now check for MyISAM Tables
my @ MyISAM_Tables ;
2019-08-26 00:30:06 +08:00
my $ sql = "SELECT `table_name` FROM INFORMATION_SCHEMA.TABLES WHERE `table_schema`='zm' AND `engine` = 'MyISAM'" ;
2020-06-10 00:18:29 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
while ( my $ dbTable = $ sth - > fetchrow ( ) ) {
push @ MyISAM_Tables , $ dbTable ;
}
$ sth - > finish ( ) ;
if ( @ MyISAM_Tables ) {
2020-06-10 01:19:19 +08:00
print ( '
Previous versions of ZoneMinder used the MyISAM database engine .
However , the recommended database engine is InnoDB .
Hint: InnoDB tables are much less likely to be corrupted during an unclean shutdown .
Press \ 'y\' to convert your tables to InnoDB or \'n\' to skip : ' ) ;
2017-05-17 23:40:54 +08:00
my $ response = <STDIN> ;
chomp ( $ response ) ;
if ( $ response =~ /^[yY]$/ ) {
$ dbh - > do ( q|SET sql_mode='traditional'| ) ; # Elevate warnings to errors
2020-06-10 01:19:19 +08:00
print "\nConverting MyISAM tables to InnoDB. Please wait.\n" ;
foreach ( @ MyISAM_Tables ) {
2019-08-26 00:30:06 +08:00
my $ sql = "ALTER TABLE `$_` ENGINE = InnoDB" ;
2020-06-10 01:19:19 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
$ sth - > finish ( ) ;
}
$ dbh - > do ( q|SET sql_mode=''| ) ; # Set mode back to default
}
}
2013-12-07 02:47:39 +08:00
} # end if interactive
2013-11-13 22:42:10 +08:00
2017-05-17 23:40:54 +08:00
if ( $ version ) {
my ( $ detaint_version ) = $ version =~ /^([\w.]+)$/ ;
$ version = $ detaint_version ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
if ( ZM_VERSION eq $ version ) {
2018-11-30 23:48:20 +08:00
print ( "\nDatabase already at version $version, update skipped.\n\n" ) ;
exit ( 0 ) ;
2017-05-17 23:40:54 +08:00
}
2013-03-17 07:45:21 +08:00
2020-06-10 01:19:19 +08:00
my $ start_zm = 0 ;
print ( "\nInitiating database upgrade to version " . ZM_VERSION . " from version $version\n" ) ;
2017-05-17 23:40:54 +08:00
if ( $ interactive ) {
2020-06-10 01:19:19 +08:00
if ( $ Config { ZM_DYN_DB_VERSION } && ( $ Config { ZM_DYN_DB_VERSION } ne $ version ) ) {
print ( "\nWARNING - You have specified an upgrade from version $version but the database version found is $Config{ZM_DYN_DB_VERSION}. Is this correct?\nPress enter to continue or ctrl-C to abort : " ) ;
2017-05-17 23:40:54 +08:00
my $ response = <STDIN> ;
2013-03-17 07:45:21 +08:00
}
2020-06-10 01:36:33 +08:00
if ( systemStatus ( ) eq 'running' ) {
print "\nZoneMinder system appears to be running. While not strictly required, it is advised to stop ZM during the update process. Would you like to stop ZM now? [Yn]:" ;
my $ response = <STDIN> ;
chomp ( $ response ) ;
if ( $ response !~ /Yy/ ) {
packageControl ( 'stop' ) ;
$ start_zm = 1 ;
}
}
2013-03-17 07:45:21 +08:00
2020-06-10 01:19:19 +08:00
print ( "\nDo you wish to take a backup of your database prior to upgrading?\nThis may result in a large file in @ZM_TMPDIR@ if you have a lot of events.\nPress 'y' for a backup or 'n' to continue : " ) ;
2020-06-10 01:36:33 +08:00
my $ response = <STDIN> ;
2020-06-10 01:19:19 +08:00
chomp ( $ response ) ;
2017-05-17 23:40:54 +08:00
while ( $ response !~ /^[yYnN]$/ ) {
2020-06-10 01:19:19 +08:00
print ( "Please press 'y' for a backup or 'n' to continue only : " ) ;
2017-05-17 23:40:54 +08:00
$ response = <STDIN> ;
2020-06-10 01:19:19 +08:00
chomp ( $ response ) ;
2017-05-17 23:40:54 +08:00
}
if ( $ response =~ /^[yY]$/ ) {
my ( $ host , $ portOrSocket ) = ( $ Config { ZM_DB_HOST } =~ /^([^:]+)(?::(.+))?$/ ) ;
2018-01-23 03:06:52 +08:00
my $ command = 'mysqldump' ;
2021-04-28 22:03:26 +08:00
if ( $ super ) {
$ command . = ' --defaults-file=/etc/mysql/debian.cnf' ;
} elsif ( $ dbUser ) {
$ command . = ' -u' . $ dbUser ;
$ command . = ' -p\'' . $ dbPass . '\'' if $ dbPass ;
}
2017-05-17 23:40:54 +08:00
if ( defined ( $ portOrSocket ) ) {
if ( $ portOrSocket =~ /^\// ) {
2020-06-04 03:36:47 +08:00
$ command . = ' -S' . $ portOrSocket ;
2017-05-17 23:40:54 +08:00
} else {
2020-06-04 03:36:47 +08:00
$ command . = ' -h' . $ host . ' -P' . $ portOrSocket ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
} else {
2020-06-04 03:36:47 +08:00
$ command . = ' -h' . $ host ;
2017-05-17 23:40:54 +08:00
}
2020-06-04 03:36:47 +08:00
my $ backup = '@ZM_TMPDIR@/' . $ Config { ZM_DB_NAME } . '-' . $ version . '.dump' ;
$ command . = ' --add-drop-table --databases ' . $ Config { ZM_DB_NAME } . ' > ' . $ backup ;
print ( "Creating backup to $backup. This may take several minutes.\n" ) ;
2020-06-02 13:54:29 +08:00
( $ command ) = $ command =~ /(.*)/ ; # detaint
2020-05-30 02:53:42 +08:00
print ( "Executing '$command'\n" ) if logDebugging ( ) ;
2017-05-17 23:40:54 +08:00
my $ output = qx( $command ) ;
my $ status = $? >> 8 ;
if ( $ status || logDebugging ( ) ) {
chomp ( $ output ) ;
print ( "Output: $output\n" ) ;
}
if ( $ status ) {
die ( "Command '$command' exited with status: $status\n" ) ;
} else {
print ( "Database successfully backed up to $backup, proceeding to upgrade.\n" ) ;
}
} elsif ( $ response !~ /^[nN]$/ ) {
die ( "Unexpected response '$response'" ) ;
}
}
print ( "\nUpgrading database to version " . ZM_VERSION . "\n" ) ;
# Update config first of all
2017-06-13 09:39:37 +08:00
migratePaths ( ) ;
2017-05-17 23:40:54 +08:00
ZoneMinder::Config:: loadConfigFromDB ( ) ;
ZoneMinder::Config:: saveConfigToDB ( ) ;
my $ cascade = undef ;
if ( $ cascade || $ version eq "1.19.0" ) {
# Patch the database
patchDB ( $ dbh , "1.19.0" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.19.1" ) {
# Patch the database
patchDB ( $ dbh , "1.19.1" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.19.2" ) {
# Patch the database
patchDB ( $ dbh , "1.19.2" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.19.3" ) {
# Patch the database
patchDB ( $ dbh , "1.19.3" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.19.4" ) {
# Rename the event directories and create a new symlink for the names
chdir ( EVENT_PATH ) ;
2013-03-17 07:45:21 +08:00
2019-08-26 00:30:06 +08:00
my $ sql = "SELECT * FROM `Monitors` ORDER BY `Id`" ;
2017-05-17 23:40:54 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
while ( my $ monitor = $ sth - > fetchrow_hashref ( ) ) {
if ( - d $ monitor - > { Name } ) {
rename ( $ monitor - > { Name } , $ monitor - > { Id } ) or warn ( "Can't rename existing monitor directory '$monitor->{Name}' to '$monitor->{Id}': $!" ) ;
symlink ( $ monitor - > { Id } , $ monitor - > { Name } ) or warn ( "Can't symlink monitor directory '$monitor->{Id}' to '$monitor->{Name}': $!" ) ;
}
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
$ sth - > finish ( ) ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
# Patch the database
patchDB ( $ dbh , "1.19.4" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.19.5" ) {
print ( "\nThis version now only uses one database user.\nPlease ensure you have run zmconfig.pl and re-entered your database username and password prior to upgrading, or the upgrade will fail.\nPress enter to continue or ctrl-C to stop : " ) ;
# Patch the database
my $ dummy = <STDIN> ;
patchDB ( $ dbh , "1.19.5" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.20.0" ) {
# Patch the database
patchDB ( $ dbh , "1.20.0" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.20.1" ) {
# Patch the database
patchDB ( $ dbh , "1.20.1" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.21.0" ) {
# Patch the database
patchDB ( $ dbh , "1.21.0" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.21.1" ) {
# Patch the database
patchDB ( $ dbh , "1.21.1" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.21.2" ) {
# Patch the database
patchDB ( $ dbh , "1.21.2" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.21.3" ) {
# Patch the database
patchDB ( $ dbh , "1.21.3" ) ;
# Add appropriate widths and heights to events
{
print ( "Updating events. This may take a few minutes. Please wait.\n" ) ;
my $ sql = "select * from Monitors order by Id" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
while ( my $ monitor = $ sth - > fetchrow_hashref ( ) ) {
2018-01-23 03:06:52 +08:00
my $ sql = 'update Events set Width = ?, Height = ? where MonitorId = ?' ;
2017-01-15 23:54:23 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
my $ res = $ sth - > execute ( $ monitor - > { Width } , $ monitor - > { Height } , $ monitor - > { Id } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
$ sth - > finish ( ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
# Add sequence numbers
2013-03-17 07:45:21 +08:00
{
2017-05-17 23:40:54 +08:00
print ( "Updating monitor sequences. Please wait.\n" ) ;
my $ sql = "select * from Monitors order by Id" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
my $ sequence = 1 ;
while ( my $ monitor = $ sth - > fetchrow_hashref ( ) ) {
2018-01-23 03:06:52 +08:00
my $ sql = 'update Monitors set Sequence = ? where Id = ?' ;
2013-03-17 07:45:21 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
my $ res = $ sth - > execute ( $ sequence + + , $ monitor - > { Id } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
$ sth - > finish ( ) ;
}
# Update saved filters
{
print ( "Updating saved filters. Please wait.\n" ) ;
my $ sql = "select * from Filters" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
my @ filters ;
while ( my $ filter = $ sth - > fetchrow_hashref ( ) ) {
push ( @ filters , $ filter ) ;
}
$ sth - > finish ( ) ;
2018-01-23 03:06:52 +08:00
$ sql = 'update Filters set Query = ? where Name = ?' ;
2017-05-17 23:40:54 +08:00
$ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
foreach my $ filter ( @ filters ) {
if ( $ filter - > { Query } =~ /op\d=&/ ) {
( my $ newQuery = $ filter - > { Query } ) =~ s/(op\d=)&/$1=&/g ;
$ res = $ sth - > execute ( $ newQuery , $ filter - > { Name } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
}
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.21.4" ) {
# Patch the database
patchDB ( $ dbh , "1.21.4" ) ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
# Convert zones to new format
2013-03-17 07:45:21 +08:00
{
2017-05-17 23:40:54 +08:00
print ( "Updating zones. Please wait.\n" ) ;
2013-03-17 07:45:21 +08:00
2017-05-17 23:40:54 +08:00
# Get the existing zones from the DB
my $ sql = "select Z.*,M.Width,M.Height from Zones as Z inner join Monitors as M on (Z.MonitorId = M.Id)" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
my @ zones ;
while ( my $ zone = $ sth - > fetchrow_hashref ( ) ) {
push ( @ zones , $ zone ) ;
}
$ sth - > finish ( ) ;
no strict 'refs' ;
foreach my $ zone ( @ zones ) {
# Create the coordinate strings
2018-01-23 03:06:52 +08:00
if ( $ zone - > { Units } eq 'Pixels' ) {
2017-05-17 23:40:54 +08:00
my $ sql = "update Zones set NumCoords = 4, Coords = concat( LoX,',',LoY,' ',HiX,',',LoY,' ',HiX,',',HiY,' ',LoX,',',HiY ), Area = round( ((HiX-LoX)+1)*((HiY-LoY)+1) ) where Id = ?" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( $ zone - > { Id } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
} else {
my $ loX = ( $ zone - > { LoX } * ( $ zone - > { Width } - 1 ) ) / 100 ;
my $ hiX = ( $ zone - > { HiX } * ( $ zone - > { Width } - 1 ) ) / 100 ;
my $ loY = ( $ zone - > { LoY } * ( $ zone - > { Height } - 1 ) ) / 100 ;
my $ hiY = ( $ zone - > { HiY } * ( $ zone - > { Height } - 1 ) ) / 100 ;
my $ area = ( ( $ hiX - $ loX ) + 1 ) * ( ( $ hiY - $ loY ) + 1 ) ;
my $ sql = "update Zones set NumCoords = 4, Coords = concat( round(?),',',round(?),' ',round(?),',',round(?),' ',round(?),',',round(?),' ',round(?),',',round(?) ), Area = round(?), MinAlarmPixels = round(?), MaxAlarmPixels = round(?), MinFilterPixels = round(?), MaxFilterPixels = round(?), MinBlobPixels = round(?), MaxBlobPixels = round(?) where Id = ?" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( $ loX , $ loY , $ hiX , $ loY , $ hiX , $ hiY , $ loX , $ hiY , $ area , ( $ zone - > { MinAlarmPixels } * $ area ) /100, ($zone->{MaxAlarmPixels}*$area)/ 100 , ( $ zone - > { MinFilterPixels } * $ area ) /100, ($zone->{MaxFilterPixels}*$area)/ 100 , ( $ zone - > { MinBlobPixels } * $ area ) /100, ($zone->{MaxBlobPixels}*$area)/ 100 , $ zone - > { Id } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
}
}
# Convert run states to new format
{
print ( "Updating run states. Please wait.\n" ) ;
# Get the existing zones from the DB
my $ sql = "select * from States" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
my @ states ;
while ( my $ state = $ sth - > fetchrow_hashref ( ) ) {
push ( @ states , $ state ) ;
}
$ sth - > finish ( ) ;
foreach my $ state ( @ states ) {
my @ new_defns ;
foreach my $ defn ( split ( /,/ , $ state - > { Definition } ) ) {
push ( @ new_defns , $ defn . ":1" ) ;
2013-03-17 07:45:21 +08:00
}
2018-01-23 03:06:52 +08:00
my $ sql = 'update States set Definition = ? where Name = ?' ;
2017-05-17 23:40:54 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( join ( ',' , @ new_defns ) , $ state - > { Name } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.22.0" ) {
# Patch the database
patchDB ( $ dbh , "1.22.0" ) ;
# Check for maximum FPS setting and update alarm max fps settings
2013-03-17 07:45:21 +08:00
{
2017-05-17 23:40:54 +08:00
print ( "Updating monitors. Please wait.\n" ) ;
if ( defined ( & ZM_NO_MAX_FPS_ON_ALARM ) && & ZM_NO_MAX_FPS_ON_ALARM ) {
# Update the individual monitor settings to match the previous global one
my $ sql = "update Monitors set AlarmMaxFPS = NULL" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
} else {
# Update the individual monitor settings to match the previous global one
my $ sql = "update Monitors set AlarmMaxFPS = MaxFPS" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
2013-03-17 07:45:21 +08:00
}
{
2017-05-17 23:40:54 +08:00
print ( "Updating mail configuration. Please wait.\n" ) ;
my ( $ sql , $ sth , $ res ) ;
if ( defined ( & ZM_EMAIL_TEXT ) && & ZM_EMAIL_TEXT ) {
my ( $ email_subject , $ email_body ) = $ Config { ZM_EMAIL_TEXT } =~ /subject\s*=\s*"([^\n]*)".*body\s*=\s*"(.*)"?$/ms ;
$ sql = "replace into Config set Id = 0, Name = 'ZM_EMAIL_SUBJECT', Value = '" . $ email_subject . "', Type = 'string', DefaultValue = 'ZoneMinder: Alarm - %MN%-%EI% (%ESM% - %ESA% %EFA%)', Hint = 'string', Pattern = '(?-xism:^(.+)\$)', Format = ' \$1 ', Prompt = 'The subject of the email used to send matching event details', Help = 'This option is used to define the subject of the email that is sent for any events that match the appropriate filters.', Category = 'mail', Readonly = '0', Requires = 'ZM_OPT_EMAIL=1'" ;
$ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
$ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
$ sql = "replace into Config set Id = 0, Name = 'ZM_EMAIL_BODY', Value = '" . $ email_body . "', Hint = 'free text', Pattern = '(?-xism:^(.+)\$)', Format = ' \$1 ', Prompt = 'The body of the email used to send matching event details', Help = 'This option is used to define the content of the email that is sent for any events that match the appropriate filters.', Category = 'mail', Readonly = '0', Requires = 'ZM_OPT_EMAIL=1'" ;
$ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
$ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
if ( defined ( & ZM_MESSAGE_TEXT ) && & ZM_MESSAGE_TEXT ) {
my ( $ message_subject , $ message_body ) = $ Config { ZM_MESSAGE_TEXT } =~ /subject\s*=\s*"([^\n]*)".*body\s*=\s*"(.*)"?$/ms ;
$ sql = "replace into Config set Id = 0, Name = 'ZM_MESSAGE_SUBJECT', Value = '" . $ message_subject . "', Type = 'string', DefaultValue = 'ZoneMinder: Alarm - %MN%-%EI%', Hint = 'string', Pattern = '(?-xism:^(.+)\$)', Format = ' \$1 ', Prompt = 'The subject of the message used to send matching event details', Help = 'This option is used to define the subject of the message that is sent for any events that match the appropriate filters.', Category = 'mail', Readonly = '0', Requires = 'ZM_OPT_MESSAGE=1'" ;
$ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
$ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
$ sql = "replace into Config set Id = 0, Name = 'ZM_MESSAGE_BODY', Value = '" . $ message_body . "', Type = 'text', DefaultValue = 'ZM alarm detected - %ED% secs, %EF%/%EFA% frames, t%EST%/m%ESM%/a%ESA% score.', Hint = 'free text', Pattern = '(?-xism:^(.+)\$)', Format = ' \$1 ', Prompt = 'The body of the message used to send matching event details', Help = 'This option is used to define the content of the message that is sent for any events that match the appropriate filters.', Category = 'mail', Readonly = '0', Requires = 'ZM_OPT_MESSAGE=1'" ;
$ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
$ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
}
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.22.1" ) {
# Patch the database
patchDB ( $ dbh , "1.22.1" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.22.2" ) {
# Patch the database
patchDB ( $ dbh , "1.22.2" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.22.3" ) {
# Patch the database
patchDB ( $ dbh , "1.22.3" ) ;
# Convert timestamp strings to new format
{
my $ sql = "select * from Monitors" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
my @ db_monitors ;
while ( my $ db_monitor = $ sth - > fetchrow_hashref ( ) ) {
push ( @ db_monitors , $ db_monitor ) ;
}
$ sth - > finish ( ) ;
foreach my $ db_monitor ( @ db_monitors ) {
if ( $ db_monitor - > { LabelFormat } =~ /\%\%s/ ) {
$ db_monitor - > { LabelFormat } =~ s/\%\%s/%N/ ;
$ db_monitor - > { LabelFormat } =~ s/\%\%s/%Q/ ;
2018-01-23 03:06:52 +08:00
my $ sql = 'update Monitors set LabelFormat = ? where Id = ?' ;
2017-05-17 23:40:54 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( $ db_monitor - > { LabelFormat } , $ db_monitor - > { Id } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
}
}
# Convert filters to new format
{
my $ sql = "select * from Filters" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
my @ dbFilters ;
while ( my $ dbFilter = $ sth - > fetchrow_hashref ( ) ) {
push ( @ dbFilters , $ dbFilter ) ;
}
$ sth - > finish ( ) ;
foreach my $ dbFilter ( @ dbFilters ) {
my % filter_terms ;
foreach my $ filter_parm ( split ( /&/ , $ dbFilter - > { Query } ) ) {
my ( $ key , $ value ) = split ( /=/ , $ filter_parm , 2 ) ;
if ( $ key ) {
$ filter_terms { $ key } = $ value ;
}
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
my $ filter = { 'terms' = > [] } ;
for ( my $ i = 1 ; $ i <= $ filter_terms { trms } ; $ i + + ) {
my $ term = { } ;
my $ conjunction_name = "cnj$i" ;
my $ obracket_name = "obr$i" ;
my $ cbracket_name = "cbr$i" ;
my $ attr_name = "attr$i" ;
my $ op_name = "op$i" ;
my $ value_name = "val$i" ;
$ term - > { cnj } = $ filter_terms { $ conjunction_name } if ( $ filter_terms { $ conjunction_name } ) ;
$ term - > { obr } = $ filter_terms { $ obracket_name } if ( $ filter_terms { $ obracket_name } ) ;
$ term - > { attr } = $ filter_terms { $ attr_name } if ( $ filter_terms { $ attr_name } ) ;
$ term - > { val } = $ filter_terms { $ value_name } if ( defined ( $ filter_terms { $ value_name } ) ) ;
$ term - > { op } = $ filter_terms { $ op_name } if ( $ filter_terms { $ op_name } ) ;
$ term - > { cbr } = $ filter_terms { $ cbracket_name } if ( $ filter_terms { $ cbracket_name } ) ;
push ( @ { $ filter - > { terms } } , $ term ) ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
$ filter - > { sort_field } = $ filter_terms { sort_field } if ( $ filter_terms { sort_field } ) ;
$ filter - > { sort_asc } = $ filter_terms { sort_asc } if ( $ filter_terms { sort_asc } ) ;
$ filter - > { limit } = $ filter_terms { limit } if ( $ filter_terms { limit } ) ;
my $ newQuery = 'a:' . int ( keys ( %$ filter ) ) . ':{s:5:"terms";a:' . int ( @ { $ filter - > { terms } } ) . ':{' ;
my $ i = 0 ;
foreach my $ term ( @ { $ filter - > { terms } } ) {
$ newQuery . = 'i:' . $ i . ';a:' . int ( keys ( %$ term ) ) . ':{' ;
while ( my ( $ key , $ val ) = each ( %$ term ) ) {
$ newQuery . = 's:' . length ( $ key ) . ':"' . $ key . '";' ;
$ newQuery . = 's:' . length ( $ val ) . ':"' . $ val . '";' ;
}
$ newQuery . = '}' ;
$ i + + ;
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
$ newQuery . = '}' ;
2018-01-23 03:06:52 +08:00
foreach my $ field ( 'sort_field' , 'sort_asc' , 'limit' ) {
2017-05-17 23:40:54 +08:00
if ( defined ( $ filter - > { $ field } ) ) {
$ newQuery . = 's:' . length ( $ field ) . ':"' . $ field . '";' ;
$ newQuery . = 's:' . length ( $ filter - > { $ field } ) . ':"' . $ filter - > { $ field } . '";' ;
}
2013-03-17 07:45:21 +08:00
}
2017-05-17 23:40:54 +08:00
$ newQuery . = '}' ;
2018-01-23 03:06:52 +08:00
my $ sql = 'update Filters set Query = ? where Name = ?' ;
2013-03-17 07:45:21 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
my $ res = $ sth - > execute ( $ newQuery , $ dbFilter - > { Name } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
}
# Update the stream quality setting to the old image quality ones
{
my $ dbh = zmDbConnect ( ) ;
my $ sql = "update Config set Value = ? where Name = 'ZM_JPEG_STREAM_QUALITY'" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( $ Config { ZM_JPEG_IMAGE_QUALITY } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.23.0" ) {
# Patch the database
patchDB ( $ dbh , "1.23.0" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.23.1" ) {
# Patch the database
patchDB ( $ dbh , "1.23.1" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.23.2" ) {
# Patch the database
patchDB ( $ dbh , "1.23.2" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.23.3" ) {
# Patch the database
patchDB ( $ dbh , "1.23.3" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.24.0" ) {
# Patch the database
patchDB ( $ dbh , "1.24.0" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.24.1" ) {
# Patch the database
patchDB ( $ dbh , "1.24.1" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.24.2" ) {
# Patch the database
patchDB ( $ dbh , "1.24.2" ) ;
$ cascade = ! undef ;
}
if ( $ cascade || $ version eq "1.24.3" ) {
my $ result = eval {
require PHP::Serialization ;
PHP::Serialization - > import ( ) ;
} ;
die ( "Unable to perform upgrade from 1.24.3, PHP::Serialization module not found" ) if ( $ result ) ;
# Patch the database
patchDB ( $ dbh , "1.24.3" ) ;
# Convert filters to JSON from PHP format serialisation
{
print ( "\nConverting filters from PHP to JSON format\n" ) ;
my $ sql = "select * from Filters" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
my @ dbFilters ;
while ( my $ dbFilter = $ sth - > fetchrow_hashref ( ) ) {
push ( @ dbFilters , $ dbFilter ) ;
}
$ sth - > finish ( ) ;
foreach my $ dbFilter ( @ dbFilters ) {
print ( " " . $ dbFilter - > { Name } ) ;
eval {
my $ phpQuery = $ dbFilter - > { Query } ;
my $ query = PHP::Serialization:: unserialize ( $ phpQuery ) ;
my $ jsonQuery = jsonEncode ( $ query ) ;
2018-01-23 03:06:52 +08:00
my $ sql = 'update Filters set Query = ? where Name = ?' ;
2017-05-17 23:40:54 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( $ jsonQuery , $ dbFilter - > { Name } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
} ;
if ( $@ ) {
print ( " - failed, please check or report. Query is '" . $ dbFilter - > { Query } . "'\n" ) ;
print ( $@ ) ;
} else {
print ( " - complete\n" ) ;
}
}
print ( "Conversion complete\n" ) ;
}
$ cascade = ! undef ;
}
2020-03-28 01:06:10 +08:00
if ( $ cascade || $ version eq '1.24.4' ) {
2017-05-17 23:40:54 +08:00
# Patch the database
2020-03-28 01:06:10 +08:00
patchDB ( $ dbh , '1.24.4' ) ;
2017-05-17 23:40:54 +08:00
# Copy the FTP specific values to the new general config
my $ fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'" ;
my $ fetchSth = $ dbh - > prepare_cached ( $ fetchSql ) or die ( "Can't prepare '$fetchSql': " . $ dbh - > errstr ( ) ) ;
2018-01-23 03:06:52 +08:00
my $ updateSql = 'update Config set Value = ? where Name = ?' ;
2017-05-17 23:40:54 +08:00
my $ updateSth = $ dbh - > prepare_cached ( $ updateSql ) or die ( "Can't prepare '$updateSql': " . $ dbh - > errstr ( ) ) ;
my $ fetchRes = $ fetchSth - > execute ( ) or die ( "Can't execute: " . $ fetchSth - > errstr ( ) ) ;
while ( my $ config = $ fetchSth - > fetchrow_hashref ( ) ) {
( my $ name = $ config - > { Name } ) =~ s/_FTP_/_/ ;
my $ updateRes = $ updateSth - > execute ( $ config - > { Value } , $ name ) or die ( "Can't execute: " . $ updateSth - > errstr ( ) ) ;
}
$ cascade = ! undef ;
}
2020-03-28 01:06:10 +08:00
if ( $ cascade || $ version lt '1.26.0' ) {
my $ sth = $ dbh - > prepare_cached ( 'SELECT * FROM Monitors LIMIT 0,1' ) ;
2017-05-17 23:40:54 +08:00
die "Error: " . $ dbh - > errstr . "\n" unless ( $ sth ) ;
die "Error: " . $ sth - > errstr . "\n" unless ( $ sth - > execute ) ;
2020-03-28 01:06:10 +08:00
my $ columns = $ sth - > { NAME } ;
2017-05-17 23:40:54 +08:00
if ( ! grep ( /^Colours$/ , @$ columns ) ) {
$ dbh - > do ( q{ alter table Monitors add column `Colours` tinyint(3) unsigned NOT NULL default '1' after `Height`; } ) ;
} # end if
if ( ! grep ( /^Deinterlacing$/ , @$ columns ) ) {
$ dbh - > do ( q{ alter table Monitors add column `Deinterlacing` INT unsigned NOT NULL default '0' after `Orientation`; } ) ;
} # end if
$ sth - > finish ( ) ;
$ cascade = ! undef ;
$ version = '1.26.0' ;
}
if ( $ version ge '1.26.0' ) {
my @ files ;
2018-01-23 03:06:52 +08:00
$ updateDir = $ Config { ZM_PATH_DATA } . '/db' if ! $ updateDir ;
2017-05-17 23:40:54 +08:00
opendir ( my $ dh , $ updateDir ) || die "Can't open updateDir $!" ;
#@files = sort grep { (!/^\./) && /^zm_update\-[\d\.]+\.sql$/ && -f "$updateDir/$_" } readdir($dh);
#PP - use perl version sort
@ files = sort {
my ( $ x ) = ( $ a =~ m/^zm_update\-(.*)\.sql$/ ) ;
my ( $ y ) = ( $ b =~ m/^zm_update\-(.*)\.sql$/ ) ;
version - > parse ( $ x ) <=> version - > parse ( $ y )
} grep { ( ! /^\./ ) && /^zm_update\-[\d\.]+\.sql$/ && - f "$updateDir/$_" } readdir ( $ dh ) ;
closedir $ dh ;
if ( ! @ files ) {
die "Should have found upgrade scripts at $updateDir\n" ;
} # end if
2020-03-28 01:06:10 +08:00
my $ sql = "UPDATE `Config` SET `Value` = ? WHERE `Name` = 'ZM_DYN_DB_VERSION'" ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
foreach my $ patch ( @ files ) {
my ( $ v ) = $ patch =~ /^zm_update\-([\d\.]+)\.sql$/ ;
#PP make sure we use version compare
2020-03-28 01:06:10 +08:00
if ( version - > parse ( 'v' . $ v ) > version - > parse ( 'v' . $ version ) ) {
print ( "Upgrading DB to $v from $version\n" ) ;
if ( patchDB ( $ dbh , $ v ) ) {
my $ res = $ sth - > execute ( $ version ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
}
2018-01-23 03:06:52 +08:00
#patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch );
} # end if newer version
2017-05-17 23:40:54 +08:00
} # end foreach patchfile
2020-03-28 01:06:10 +08:00
$ sth - > finish ( ) ;
2017-05-17 23:40:54 +08:00
$ cascade = ! undef ;
} # end if
if ( $ cascade ) {
2020-03-28 01:06:10 +08:00
# This is basically here so that we don't need zm-update-blah.sql files for versions without db changes
my $ sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = ?' ;
2017-05-17 23:40:54 +08:00
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
2020-03-28 01:06:10 +08:00
$ sth - > execute ( ZM_VERSION , 'ZM_DYN_DB_VERSION' ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
$ sth - > execute ( ZM_VERSION , 'ZM_DYN_CURR_VERSION' ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2017-05-17 23:40:54 +08:00
$ sth - > finish ( ) ;
} else {
zmDbDisconnect ( ) ;
die ( "Can't find upgrade from version '$version'" ) ;
}
2018-08-31 01:25:02 +08:00
# Re-enable the privacy popup after each upgrade
2019-03-19 02:42:05 +08:00
#my $sql = "update Config set Value = 1 where Name = 'ZM_SHOW_PRIVACY'";
#my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
#my $res = $sth->execute( ) or die( "Can't execute: ".$sth->errstr() );
#$sth->finish();
2020-06-10 01:19:19 +08:00
2020-03-28 01:06:10 +08:00
print ( "\nDatabase upgrade to version " . ZM_VERSION . " successful.\n\n" ) ;
2020-06-10 01:19:19 +08:00
if ( $ start_zm ) {
print ( "Starting ZM since we stopped it for the update\n" ) ;
packageControl ( 'start' ) ;
}
2020-03-28 01:06:10 +08:00
} # end if version
2013-11-14 00:45:53 +08:00
zmDbDisconnect ( ) ;
2020-03-28 01:06:10 +08:00
exit ( 0 ) ;
2017-05-18 05:47:39 +08:00
2018-01-23 03:06:52 +08:00
sub patchDB_using_do {
my ( $ dbh , $ version , $ file ) = @ _ ;
2020-03-28 01:06:10 +08:00
open ( my $ fh , '<' , $ file ) or die "Unable to open $file $!" ;
2018-01-23 03:06:52 +08:00
$/ = undef ;
my $ sql = <$fh> ;
close $ fh ;
if ( $ sql ) {
2020-03-28 01:06:10 +08:00
$ dbh - > { AutoCommit } = 0 ;
2018-01-23 03:06:52 +08:00
$ dbh - > do ( $ sql ) ;
if ( $ dbh - > errstr ( ) ) {
$ dbh - > rollback ( ) ;
2020-03-28 01:06:10 +08:00
die 'Error: ' . $ dbh - > errstr ( ) . ". Rolled back.\n" ;
2018-01-23 03:06:52 +08:00
} # end if error
2020-03-28 01:06:10 +08:00
my $ sql = 'UPDATE `Config` SET `Value` = ? WHERE `Name` = \'ZM_DYN_DB_VERSION\'' ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die "Can't prepare '$sql': " . $ dbh - > errstr ( ) ;
my $ res = $ sth - > execute ( $ version ) or die 'Can\'t execute: ' . $ sth - > errstr ( ) ;
2018-01-23 03:06:52 +08:00
$ sth - > finish ( ) ;
2020-03-28 01:06:10 +08:00
$ dbh - > { AutoCommit } = 1 ;
2018-01-23 03:06:52 +08:00
} else {
Warning ( "Empty db update file at $file" ) ;
}
2020-03-28 01:06:10 +08:00
} # end sub patchDB_using_do
2017-05-18 05:47:39 +08:00
sub patchDB {
my $ dbh = shift ;
my $ version = shift ;
2020-06-04 23:28:26 +08:00
my ( $ host , $ portOrSocket ) = ( $ Config { ZM_DB_HOST } =~ /^([^:]+)(?::(.+))?$/ ) if $ Config { ZM_DB_HOST } ;
2018-01-05 06:16:43 +08:00
my $ command = 'mysql' ;
2021-04-28 22:03:26 +08:00
if ( $ super ) {
$ command . = ' --defaults-file=/etc/mysql/debian.cnf' ;
} elsif ( $ dbUser ) {
$ command . = ' -u' . $ dbUser ;
$ command . = ' -p\'' . $ dbPass . '\'' if $ dbPass ;
}
2018-01-05 06:16:43 +08:00
if ( defined ( $ portOrSocket ) ) {
if ( $ portOrSocket =~ /^\// ) {
$ command . = ' -S' . $ portOrSocket ;
} else {
$ command . = ' -h' . $ host . ' -P' . $ portOrSocket ;
}
2020-06-04 23:28:26 +08:00
} elsif ( $ host ) {
2018-01-05 06:16:43 +08:00
$ command . = ' -h' . $ host ;
}
$ command . = ' ' . $ Config { ZM_DB_NAME } . ' < ' ;
if ( $ updateDir ) {
$ command . = $ updateDir ;
} else {
$ command . = $ Config { ZM_PATH_DATA } . '/db' ;
}
$ command . = '/zm_update-' . $ version . '.sql' ;
2017-05-18 05:47:39 +08:00
2020-03-28 01:06:10 +08:00
print ( "Executing '$command'\n" ) if logDebugging ( ) ;
2020-06-02 13:54:29 +08:00
( $ command ) = $ command =~ /(.*)/ ; # detaint
2018-01-05 06:16:43 +08:00
my $ output = qx( $command ) ;
my $ status = $? >> 8 ;
if ( $ status || logDebugging ( ) ) {
2020-03-28 01:06:10 +08:00
chomp ( $ output ) ;
print ( "Output: $output\n" ) ;
2018-01-05 06:16:43 +08:00
}
if ( $ status ) {
2020-03-28 01:06:10 +08:00
die ( "Command '$command' exited with status: $status\n" ) ;
2018-01-05 06:16:43 +08:00
}
2020-03-28 01:06:10 +08:00
print ( "\nDatabase successfully upgraded to version $version.\n" ) ;
} # end sub patchDB
2017-05-18 05:47:39 +08:00
2019-05-13 22:31:09 +08:00
sub migratePasswords {
2020-03-28 01:06:10 +08:00
print ( "Migratings passwords, if any...\n" ) ;
my $ sql = 'SELECT * FROM `Users`' ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
while ( my $ user = $ sth - > fetchrow_hashref ( ) ) {
my $ scheme = substr ( $ user - > { Password } , 0 , 1 ) ;
if ( $ scheme eq '*' ) {
print ( '-->' . $ user - > { Username } . " password will be migrated\n" ) ;
my $ salt = Crypt::Eksblowfish::Bcrypt:: en_base64 ( rand_bits ( 16 * 8 ) ) ;
my $ settings = '$2a$10$' . $ salt ;
my $ pass_hash = Crypt::Eksblowfish::Bcrypt:: bcrypt ( $ user - > { Password } , $ settings ) ;
my $ new_pass_hash = '-ZM-' . $ pass_hash ;
$ sql = 'UPDATE Users SET `Password`=? WHERE `Username`=?' ;
my $ sth = $ dbh - > prepare_cached ( $ sql ) or die ( "Can't prepare '$sql': " . $ dbh - > errstr ( ) ) ;
my $ res = $ sth - > execute ( $ new_pass_hash , $ user - > { Username } ) or die ( "Can't execute: " . $ sth - > errstr ( ) ) ;
2019-05-13 22:31:09 +08:00
}
2020-03-28 01:06:10 +08:00
}
} # end sub migratePasswords
2019-05-13 22:31:09 +08:00
2017-06-13 09:39:37 +08:00
sub migratePaths {
2017-06-14 06:02:28 +08:00
my $ customConfigFile = '@ZM_CONFIG_SUBDIR@/zmcustom.conf' ;
2017-06-13 09:39:37 +08:00
2017-06-14 06:02:28 +08:00
if ( ( ! - e $ customConfigFile ) && ( ZM_VERSION ge '1.31.0' ) && ( $ Config { ZM_DYN_DB_VERSION } lt '1.31.1' ) ) {
2017-06-13 09:39:37 +08:00
2017-06-14 06:02:28 +08:00
my % customConfig ;
2017-06-13 09:39:37 +08:00
2017-06-14 06:02:28 +08:00
# Check the traditional default values for the variables previsouly found under Options -> Paths
if ( $ Config { ZM_DIR_EVENTS } ne 'events' ) {
$ customConfig { ZM_DIR_EVENTS } = $ Config { ZM_DIR_EVENTS } ;
}
if ( $ Config { ZM_DIR_IMAGES } ne 'images' ) {
$ customConfig { ZM_DIR_IMAGES } = $ Config { ZM_DIR_IMAGES } ;
}
if ( $ Config { ZM_DIR_SOUNDS } ne 'sounds' ) {
$ customConfig { ZM_DIR_SOUNDS } = $ Config { ZM_DIR_SOUNDS } ;
}
if ( $ Config { ZM_PATH_ZMS } ne '@ZM_PATH_ZMS@' ) {
$ customConfig { ZM_PATH_ZMS } = $ Config { ZM_PATH_ZMS } ;
}
if ( $ Config { ZM_PATH_MAP } ne '/dev/shm' ) {
$ customConfig { ZM_PATH_MAP } = $ Config { ZM_PATH_MAP } ;
}
if ( $ Config { ZM_PATH_SOCKS } ne '@ZM_SOCKDIR@' ) {
$ customConfig { ZM_PATH_SOCKS } = $ Config { ZM_PATH_SOCKS } ;
}
if ( $ Config { ZM_PATH_LOGS } ne '@ZM_LOGDIR@' ) {
$ customConfig { ZM_PATH_LOGS } = $ Config { ZM_PATH_LOGS } ;
}
if ( $ Config { ZM_PATH_SWAP } ne '@ZM_TMPDIR@' ) {
$ customConfig { ZM_PATH_SWAP } = $ Config { ZM_PATH_SWAP } ;
}
if ( $ Config { ZM_PATH_ARP } ne '' ) {
$ customConfig { ZM_PATH_ARP } = $ Config { ZM_PATH_ARP } ;
}
2017-06-13 09:39:37 +08:00
2017-06-14 06:02:28 +08:00
# If any variables differ from their expected default value,
# save them to a config file before they get purged from the database
if ( % customConfig ) {
print ( "\nMigrating custom config values from Options -> Paths\nto $customConfigFile.\n" ) ;
print ( "\nPlease verify these values before starting ZoneMinder.\n\n" ) ;
open ( my $ fh , '>' , $ customConfigFile ) or die "Could open $customConfigFile for writing: $!." ;
print $ fh "# These values were autogenerated by zmupdate.pl\n" ;
print $ fh "# You may edit these values. ZoneMinder will not overwrite them.\n" ;
print $ fh "#\n\n" ;
while ( my ( $ key , $ value ) = each % customConfig ) {
print $ fh "$key=$value\n" ;
}
close $ fh ;
my $ gid = getgrnam ( '@ZM_WEB_GROUP@' ) ;
chown - 1 , $ gid , $ customConfigFile ;
chmod 0640 , $ customConfigFile ;
2017-06-13 09:39:37 +08:00
}
2017-06-14 06:02:28 +08:00
}
2017-06-13 09:39:37 +08:00
}
2017-05-18 05:47:39 +08:00
1 ;
__END__