Merge pull request #879 from SteveGilvarry/feature-h264-videostorage
Merging Master to feature-h264-videostorage
This commit is contained in:
commit
564d85161d
|
@ -32,8 +32,8 @@ install:
|
|||
- sudo make install-libs
|
||||
before_script:
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize --force; fi
|
||||
- if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal; fi
|
||||
- if [ "$ZM_BUILDMETHOD" = "autotools" ]; then libtoolize -v --force; fi
|
||||
- if [ "$ZM_BUILDMETHOD" = "autotools" ]; then aclocal -I m4; fi
|
||||
- if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoheader; fi
|
||||
- if [ "$ZM_BUILDMETHOD" = "autotools" ]; then automake --force-missing --add-missing; fi
|
||||
- if [ "$ZM_BUILDMETHOD" = "autotools" ]; then autoconf; fi
|
||||
|
|
258
CMakeLists.txt
258
CMakeLists.txt
|
@ -1,25 +1,28 @@
|
|||
# Main CMake file for the ZoneMinder project.
|
||||
# Created by mastertheknife (Kfir Itzhak)
|
||||
# The goal is to ease up the installation of zoneminder.
|
||||
# Our current installation method (using autotools) is outdated, slow and breaks now and then.
|
||||
# The CMake installation method will require no parameters at all, default should sufficient and reliable.
|
||||
# It will be still possible to install ZoneMinder using autotools, they don't conflict with each other. The cmake way is a complete re-write (different syntax) and aims to be identical to the autotools way,
|
||||
# by having options using the same name and leaving ZM totally unmodified, while providing exactly the same things that ZM expects (config.h, configuration in *.in files, etc).
|
||||
#
|
||||
# For more information and installation, see the INSTALL file
|
||||
#
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (zoneminder)
|
||||
set(zoneminder_VERSION "1.28.1")
|
||||
|
||||
# CMake does not allow out-of-source build if CMakeCache.exists in the source folder. Abort and notify the user to save him from headache why it doesn't work.
|
||||
if((NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt"))
|
||||
message(FATAL_ERROR " You are attempting to do an out-of-source build, but a cmake cache file for an in-source build exists. Please delete the file CMakeCache.txt from the source folder to proceed.")
|
||||
endif((NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt"))
|
||||
# CMake does not allow out-of-source build if CMakeCache.exists
|
||||
# in the source folder. Abort and notify the user
|
||||
if(
|
||||
(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt"))
|
||||
message(FATAL_ERROR " You are attempting to do an out-of-source build,
|
||||
but a cmake cache file for an in-source build exists. Please delete
|
||||
the file CMakeCache.txt from the source folder to proceed.")
|
||||
endif(
|
||||
(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
AND (EXISTS "${CMAKE_SOURCE_DIR}/CMakeCache.txt"))
|
||||
|
||||
# Default build type. To change the build type, use the CMAKE_BUILD_TYPE configuration option.
|
||||
# Default build type. To change the build type,
|
||||
# use the CMAKE_BUILD_TYPE configuration option.
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type: Release or Debug" FORCE)
|
||||
set(CMAKE_BUILD_TYPE
|
||||
Release CACHE STRING "Build type: Release or Debug" FORCE)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
# Can assist in troubleshooting
|
||||
|
@ -42,35 +45,80 @@ include (CheckFunctionExists)
|
|||
include (CheckPrototypeDefinition_fixed)
|
||||
include (CheckTypeSize)
|
||||
include (CheckStructHasMember)
|
||||
include (CheckSendfile)
|
||||
|
||||
# Configuration options
|
||||
mark_as_advanced(FORCE ZM_EXTRA_LIBS ZM_MYSQL_ENGINE ZM_NO_MMAP CMAKE_INSTALL_FULL_BINDIR ZM_PERL_SUBPREFIX ZM_PERL_USE_PATH ZM_TARGET_DISTRO ZM_CONFIG_DIR)
|
||||
set(ZM_RUNDIR "/var/run/zm" CACHE PATH "Location of transient process files, default: /var/run/zm")
|
||||
set(ZM_SOCKDIR "/var/run/zm" CACHE PATH "Location of Unix domain socket files, default /var/run/zm")
|
||||
set(ZM_TMPDIR "/var/tmp/zm" CACHE PATH "Location of temporary files, default: /tmp/zm")
|
||||
set(ZM_LOGDIR "/var/log/zm" CACHE PATH "Location of generated log files, default: /var/log/zm")
|
||||
set(ZM_WEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/www" CACHE PATH "Location of the web files, default: <prefix>/${CMAKE_INSTALL_DATADIR}/zoneminder/www")
|
||||
set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH "Location of the cgi-bin files, default: <prefix>/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin")
|
||||
set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH "Location of dynamic content (events and images), default: /var/lib/zoneminder")
|
||||
set(ZM_DB_HOST "localhost" CACHE STRING "Hostname where ZoneMinder database located, default: localhost")
|
||||
set(ZM_DB_NAME "zm" CACHE STRING "Name of ZoneMinder database, default: zm")
|
||||
set(ZM_DB_USER "zmuser" CACHE STRING "Name of ZoneMinder database user, default: zmuser")
|
||||
set(ZM_DB_PASS "zmpass" CACHE STRING "Password of ZoneMinder database user, default: zmpass")
|
||||
set(ZM_WEB_USER "" CACHE STRING "The user apache or the local web server runs on. Leave empty for automatic detection. If that fails, you can use this variable to force")
|
||||
set(ZM_WEB_GROUP "" CACHE STRING "The group apache or the local web server runs on, Leave empty to be the same as the web user")
|
||||
mark_as_advanced(
|
||||
FORCE ZM_EXTRA_LIBS
|
||||
ZM_MYSQL_ENGINE
|
||||
ZM_NO_MMAP
|
||||
CMAKE_INSTALL_FULL_BINDIR
|
||||
ZM_PERL_MM_PARMS
|
||||
ZM_PERL_SEARCH_PATH
|
||||
ZM_TARGET_DISTRO
|
||||
ZM_CONFIG_DIR)
|
||||
|
||||
set(ZM_RUNDIR "/var/run/zm" CACHE PATH
|
||||
"Location of transient process files, default: /var/run/zm")
|
||||
set(ZM_SOCKDIR "/var/run/zm" CACHE PATH
|
||||
"Location of Unix domain socket files, default /var/run/zm")
|
||||
set(ZM_TMPDIR "/var/tmp/zm" CACHE PATH
|
||||
"Location of temporary files, default: /tmp/zm")
|
||||
set(ZM_LOGDIR "/var/log/zm" CACHE PATH
|
||||
"Location of generated log files, default: /var/log/zm")
|
||||
set(ZM_WEBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/zoneminder/www" CACHE PATH
|
||||
"Location of the web files, default: <prefix>/${CMAKE_INSTALL_DATADIR}/zoneminder/www")
|
||||
set(ZM_CGIDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin" CACHE PATH
|
||||
"Location of the cgi-bin files, default: <prefix>/${CMAKE_INSTALL_LIBEXECDIR}/zoneminder/cgi-bin")
|
||||
set(ZM_CONTENTDIR "/var/lib/zoneminder" CACHE PATH
|
||||
"Location of dynamic content (events and images), default: /var/lib/zoneminder")
|
||||
set(ZM_DB_HOST "localhost" CACHE STRING
|
||||
"Hostname where ZoneMinder database located, default: localhost")
|
||||
set(ZM_DB_NAME "zm" CACHE STRING
|
||||
"Name of ZoneMinder database, default: zm")
|
||||
set(ZM_DB_USER "zmuser" CACHE STRING
|
||||
"Name of ZoneMinder database user, default: zmuser")
|
||||
set(ZM_DB_PASS "zmpass" CACHE STRING
|
||||
"Password of ZoneMinder database user, default: zmpass")
|
||||
set(ZM_WEB_USER "" CACHE STRING
|
||||
"The user apache or the local web server runs on. Leave empty for automatic detection.
|
||||
If that fails, you can use this variable to force")
|
||||
set(ZM_WEB_GROUP "" CACHE STRING
|
||||
"The group apache or the local web server runs on,
|
||||
Leave empty to be the same as the web user")
|
||||
# Advanced
|
||||
set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH "Location of ZoneMinder configuration, default system config directory")
|
||||
set(ZM_EXTRA_LIBS "" CACHE STRING "A list of optional libraries, separated by semicolons, e.g. ssl;theora")
|
||||
set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING "MySQL engine to use with database, default: InnoDB")
|
||||
set(ZM_NO_MMAP "OFF" CACHE BOOL "Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF")
|
||||
set(ZM_NO_FFMPEG "OFF" CACHE BOOL "Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. default: OFF")
|
||||
set(ZM_NO_LIBVLC "OFF" CACHE BOOL "Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF")
|
||||
set(ZM_NO_CURL "OFF" CACHE BOOL "Set to ON to skip cURL checks and force building ZM without cURL. default: OFF")
|
||||
set(ZM_NO_X10 "OFF" CACHE BOOL "Set to ON to build ZoneMinder without X10 support. default: OFF")
|
||||
set(ZM_ONVIF "OFF" CACHE BOOL "Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not work with all cameras claiming to be ONVIF compliant. default: OFF")
|
||||
set(ZM_PERL_SUBPREFIX "${CMAKE_INSTALL_LIBDIR}/perl5" CACHE PATH "Use a different directory for the zm perl modules. NOTE: This is a subprefix, e.g. lib will be turned into <prefix>/lib, default: <libdir>/perl5")
|
||||
set(ZM_PERL_USE_PATH "${CMAKE_INSTALL_PREFIX}/${ZM_PERL_SUBPREFIX}" CACHE PATH "Override the include path for zm perl modules. Useful if you are moving the perl modules without using the ZM_PERL_SUBPREFIX option. default: <prefix>/<zmperlsubprefix>")
|
||||
set(ZM_TARGET_DISTRO "" CACHE STRING "Build ZoneMinder for a specific distribution. Currently, valid names are: f21, f20, el6, OS13")
|
||||
set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH
|
||||
"Location of ZoneMinder configuration, default system config directory")
|
||||
set(ZM_EXTRA_LIBS "" CACHE STRING
|
||||
"A list of optional libraries, separated by semicolons, e.g. ssl;theora")
|
||||
set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING
|
||||
"MySQL engine to use with database, default: InnoDB")
|
||||
set(ZM_NO_MMAP "OFF" CACHE BOOL
|
||||
"Set to ON to not use mmap shared memory. Shouldn't be enabled unless you
|
||||
experience problems with the shared memory. default: OFF")
|
||||
set(ZM_NO_FFMPEG "OFF" CACHE BOOL
|
||||
"Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. default: OFF")
|
||||
set(ZM_NO_LIBVLC "OFF" CACHE BOOL
|
||||
"Set to ON to skip libvlc checks and force building ZM without libvlc. default: OFF")
|
||||
set(ZM_NO_CURL "OFF" CACHE BOOL
|
||||
"Set to ON to skip cURL checks and force building ZM without cURL. default: OFF")
|
||||
set(ZM_NO_X10 "OFF" CACHE BOOL
|
||||
"Set to ON to build ZoneMinder without X10 support. default: OFF")
|
||||
set(ZM_ONVIF "OFF" CACHE BOOL
|
||||
"Set to ON to enable basic ONVIF support. This is EXPERIMENTAL and may not
|
||||
work with all cameras claiming to be ONVIF compliant. default: OFF")
|
||||
set(ZM_PERL_MM_PARMS INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1 CACHE STRING
|
||||
"By default, ZoneMinder's Perl modules are installed into the Vendor folders,
|
||||
as defined by your installation of Perl. You can change that here. Consult Perl's
|
||||
MakeMaker documentation for a definition of acceptable parameters. If you set this
|
||||
to something that causes the modules to be installed outside Perl's normal search
|
||||
path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly.")
|
||||
set(ZM_PERL_SEARCH_PATH "" CACHE PATH
|
||||
"Use to add a folder to your Perl's search path. This will need to be set in cases
|
||||
where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are
|
||||
installed outside Perl's default search path.")
|
||||
set(ZM_TARGET_DISTRO "" CACHE STRING
|
||||
"Build ZoneMinder for a specific distribution. Currently, valid names are: f21, f20, el6, OS13")
|
||||
|
||||
# Reassign some variables if a target distro has been specified
|
||||
if((ZM_TARGET_DISTRO STREQUAL "f21") OR (ZM_TARGET_DISTRO STREQUAL "f20"))
|
||||
|
@ -105,14 +153,40 @@ elseif(ZM_TARGET_DISTRO STREQUAL "OS13")
|
|||
endif((ZM_TARGET_DISTRO STREQUAL "f21") OR (ZM_TARGET_DISTRO STREQUAL "f20"))
|
||||
|
||||
# Required for certain checks to work
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES} stdio.h stdlib.h math.h signal.h)
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES
|
||||
${CMAKE_EXTRA_INCLUDE_FILES} stdio.h stdlib.h math.h signal.h
|
||||
)
|
||||
# Required for including headers from the this folder
|
||||
include_directories("${CMAKE_BINARY_DIR}")
|
||||
# This is required to enable searching in lib64 (if exists), do not change
|
||||
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
|
||||
|
||||
# Host OS Check
|
||||
set(HOST_OS "")
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(HOST_OS "linux")
|
||||
endif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES ".*(SunOS|Solaris).*")
|
||||
set(HOST_OS "solaris")
|
||||
set(SOLARIS 1)
|
||||
endif(${CMAKE_SYSTEM_NAME} MATCHES ".*(SunOS|Solaris).*")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD.*")
|
||||
set(HOST_OS "BSD")
|
||||
set(BSD 1)
|
||||
endif(${CMAKE_SYSTEM_NAME} MATCHES ".*BSD.*")
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
set(HOST_OS "darwin")
|
||||
endif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
if(NOT HOST_OS)
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder was unable to deterimine the host OS. Please report this. Value of CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
|
||||
endif(NOT HOST_OS)
|
||||
|
||||
# System checks
|
||||
check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H)
|
||||
check_include_file("libv4l1-videodev.h" HAVE_LIBV4L1_VIDEODEV_H)
|
||||
if(NOT HAVE_LIBV4L1_VIDEODEV_H)
|
||||
check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H)
|
||||
endif(NOT HAVE_LIBV4L1_VIDEODEV_H)
|
||||
check_include_file("linux/videodev2.h" HAVE_LINUX_VIDEODEV2_H)
|
||||
check_include_file("execinfo.h" HAVE_EXECINFO_H)
|
||||
check_include_file("ucontext.h" HAVE_UCONTEXT_H)
|
||||
|
@ -167,10 +241,12 @@ if(JPEG_FOUND)
|
|||
set(CMAKE_REQUIRED_INCLUDES "${JPEG_INCLUDE_DIR}")
|
||||
check_include_files("stdio.h;jpeglib.h" HAVE_JPEGLIB_H)
|
||||
if(NOT HAVE_JPEGLIB_H)
|
||||
message(FATAL_ERROR " zm requires libjpeg headers - check that libjpeg development packages are installed")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires libjpeg headers - check that libjpeg development packages are installed")
|
||||
endif(NOT HAVE_JPEGLIB_H)
|
||||
else(JPEG_FOUND)
|
||||
message(FATAL_ERROR "zm requires jpeg but it was not found on your system")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires jpeg but it was not found on your system")
|
||||
endif(JPEG_FOUND)
|
||||
|
||||
# OpenSSL
|
||||
|
@ -200,10 +276,12 @@ if(PTHREAD_LIBRARIES)
|
|||
mark_as_advanced(FORCE PTHREAD_LIBRARIES PTHREAD_INCLUDE_DIR)
|
||||
check_include_file("pthread.h" HAVE_PTHREAD_H)
|
||||
if(NOT HAVE_PTHREAD_H)
|
||||
message(FATAL_ERROR " zm requires pthread headers - check that pthread development packages are installed")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires pthread headers - check that pthread development packages are installed")
|
||||
endif(NOT HAVE_PTHREAD_H)
|
||||
else(PTHREAD_LIBRARIES)
|
||||
message(FATAL_ERROR "zm requires pthread but it was not found on your system")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires pthread but it was not found on your system")
|
||||
endif(PTHREAD_LIBRARIES)
|
||||
|
||||
# pcre (using find_library and find_path)
|
||||
|
@ -275,10 +353,12 @@ if(MYSQLCLIENT_LIBRARIES)
|
|||
mark_as_advanced(FORCE MYSQLCLIENT_LIBRARIES MYSQLCLIENT_INCLUDE_DIR)
|
||||
check_include_file("mysql/mysql.h" HAVE_MYSQL_H)
|
||||
if(NOT HAVE_MYSQL_H)
|
||||
message(FATAL_ERROR "zm requires MySQL headers - check that MySQL development packages are installed")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires MySQL headers - check that MySQL development packages are installed")
|
||||
endif(NOT HAVE_MYSQL_H)
|
||||
else(MYSQLCLIENT_LIBRARIES)
|
||||
message(FATAL_ERROR "zm requires mysqlclient but it was not found on your system")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires mysqlclient but it was not found on your system")
|
||||
endif(MYSQLCLIENT_LIBRARIES)
|
||||
|
||||
# x264 (using find_library and find_path)
|
||||
|
@ -458,7 +538,8 @@ endif(NOT ZM_NO_LIBVLC)
|
|||
|
||||
# Check for gnutls or crypto
|
||||
if((NOT HAVE_LIBCRYPTO) AND (NOT HAVE_LIBGNUTLS))
|
||||
message(FATAL_ERROR " zm requires crypto or gnutls but none were found on your system")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires crypto or gnutls but none were found on your system")
|
||||
endif((NOT HAVE_LIBCRYPTO) AND (NOT HAVE_LIBGNUTLS))
|
||||
|
||||
# Check for V4L header files and enable ZM_HAS_V4L, ZM_HAS_V4L1, ZM_HAS_V4L2 accordingly
|
||||
|
@ -466,17 +547,22 @@ endif((NOT HAVE_LIBCRYPTO) AND (NOT HAVE_LIBGNUTLS))
|
|||
set(ZM_HAS_V4L 0)
|
||||
set(ZM_HAS_V4L1 0)
|
||||
set(ZM_HAS_V4L2 0)
|
||||
if(HAVE_LINUX_VIDEODEV_H)
|
||||
if(HAVE_LINUX_VIDEODEV_H OR HAVE_LIBV4L1_VIDEODEV_H)
|
||||
set(ZM_HAS_V4L 1)
|
||||
set(ZM_HAS_V4L1 1)
|
||||
endif(HAVE_LINUX_VIDEODEV_H)
|
||||
endif(HAVE_LINUX_VIDEODEV_H OR HAVE_LIBV4L1_VIDEODEV_H)
|
||||
if(HAVE_LINUX_VIDEODEV2_H)
|
||||
set(ZM_HAS_V4L 1)
|
||||
set(ZM_HAS_V4L2 1)
|
||||
endif(HAVE_LINUX_VIDEODEV2_H)
|
||||
if((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H))
|
||||
message(AUTHOR_WARNING " Video 4 Linux headers weren't found - Analog and USB camera support will not be available")
|
||||
endif((NOT HAVE_LINUX_VIDEODEV_H) AND (NOT HAVE_LINUX_VIDEODEV2_H))
|
||||
if((NOT HAVE_LINUX_VIDEODEV_H)
|
||||
AND (NOT HAVE_LIBV4L1_VIDEODEV_H)
|
||||
AND (NOT HAVE_LINUX_VIDEODEV2_H))
|
||||
message(AUTHOR_WARNING
|
||||
"Video 4 Linux headers weren't found - Analog and USB camera support will not be available")
|
||||
endif((NOT HAVE_LINUX_VIDEODEV_H)
|
||||
AND (NOT HAVE_LIBV4L1_VIDEODEV_H)
|
||||
AND (NOT HAVE_LINUX_VIDEODEV2_H))
|
||||
# Check for PCRE and enable ZM_PCRE accordingly
|
||||
set(ZM_PCRE 0)
|
||||
if(HAVE_LIBPCRE AND HAVE_PCRE_H)
|
||||
|
@ -497,26 +583,37 @@ if(ZM_ONVIF)
|
|||
set(ZM_HAS_ONVIF 1)
|
||||
endif(ZM_ONVIF)
|
||||
|
||||
# Check for authenication functions
|
||||
# Check for authentication functions
|
||||
if(HAVE_OPENSSL_MD5_H)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
|
||||
check_prototype_definition(MD5 "unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)" "NULL" "openssl/md5.h" HAVE_MD5_OPENSSL)
|
||||
check_prototype_definition(
|
||||
MD5
|
||||
"unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md)" "NULL" "openssl/md5.h"
|
||||
HAVE_MD5_OPENSSL)
|
||||
endif(HAVE_OPENSSL_MD5_H)
|
||||
if(HAVE_GNUTLS_OPENSSL_H)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}")
|
||||
check_prototype_definition(MD5 "unsigned char *MD5 (const unsigned char *buf, unsigned long len, unsigned char *md)" "NULL" "gnutls/openssl.h" HAVE_MD5_GNUTLS)
|
||||
check_prototype_definition(
|
||||
MD5
|
||||
"unsigned char *MD5 (const unsigned char *buf, unsigned long len, unsigned char *md)" "NULL" "gnutls/openssl.h"
|
||||
HAVE_MD5_GNUTLS)
|
||||
endif(HAVE_GNUTLS_OPENSSL_H)
|
||||
if(HAVE_GNUTLS_GNUTLS_H)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARIES}")
|
||||
set(CMAKE_REQUIRED_INCLUDES "${GNUTLS_INCLUDE_DIR}")
|
||||
check_prototype_definition(gnutls_fingerprint "int gnutls_fingerprint (gnutls_digest_algorithm_t algo, const gnutls_datum_t * data, void *result, size_t * result_size)" "0" "stdlib.h;gnutls/gnutls.h" HAVE_DECL_GNUTLS_FINGERPRINT)
|
||||
check_prototype_definition(
|
||||
gnutls_fingerprint
|
||||
"int gnutls_fingerprint (gnutls_digest_algorithm_t algo, const gnutls_datum_t * data, void *result, size_t * result_size)" "0" "stdlib.h;gnutls/gnutls.h"
|
||||
HAVE_DECL_GNUTLS_FINGERPRINT)
|
||||
endif(HAVE_GNUTLS_GNUTLS_H)
|
||||
if(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS)
|
||||
set(HAVE_DECL_MD5 1)
|
||||
else(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS)
|
||||
message(AUTHOR_WARNING " ZM requires a working MD5 function for hashed authenication but none were found - hashed authenication will not be available")
|
||||
message(AUTHOR_WARNING
|
||||
"ZoneMinder requires a working MD5 function for hashed authenication but
|
||||
none were found - hashed authenication will not be available")
|
||||
endif(HAVE_MD5_OPENSSL OR HAVE_MD5_GNUTLS)
|
||||
# Dirty fix for zm_user only using openssl's md5 if gnutls and gcrypt are not available.
|
||||
# This needs to be fixed in zm_user.[h,cpp] but such fix will also require changes to configure.ac
|
||||
|
@ -528,26 +625,40 @@ endif(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL)
|
|||
# Check for Perl
|
||||
find_package(Perl)
|
||||
if(NOT PERL_FOUND)
|
||||
message(FATAL_ERROR "zm requires Perl 5.6.0 or newer but it was not found on your system")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder requires Perl 5.6.0 or newer but it was not found on your system")
|
||||
endif(NOT PERL_FOUND)
|
||||
|
||||
# Checking for perl modules requires FindPerlModules.cmake
|
||||
# Check all required modules at once
|
||||
# TODO: Add checking for the optional modules
|
||||
find_package(PerlModules COMPONENTS Sys::Syslog DBI DBD::mysql Getopt::Long Time::HiRes Date::Manip LWP::UserAgent ExtUtils::MakeMaker ${ZM_MMAP_PERLPACKAGE})
|
||||
find_package(
|
||||
PerlModules COMPONENTS Sys::Syslog DBI DBD::mysql
|
||||
Getopt::Long Time::HiRes Date::Manip LWP::UserAgent
|
||||
ExtUtils::MakeMaker ${ZM_MMAP_PERLPACKAGE})
|
||||
if(NOT PERLMODULES_FOUND)
|
||||
message(FATAL_ERROR "Not all required perl modules were found on your system")
|
||||
message(FATAL_ERROR
|
||||
"Not all required perl modules were found on your system")
|
||||
endif(NOT PERLMODULES_FOUND)
|
||||
|
||||
# Attempt to check which user apache (or other web server) runs on by searching for a user beginning with apache or www and then cutting the user from the first matching user line
|
||||
# Attempt to check which user apache (or other web server) runs on by
|
||||
# searching for a user beginning with apache or www and then cutting the user
|
||||
# from the first matching user line
|
||||
if(ZM_WEB_USER STREQUAL "")
|
||||
# Check for a user matching ^apache and cut the username from the userline in the first match
|
||||
# Check for a user matching ^apache and cut the username from the
|
||||
# userline in the first match
|
||||
file(STRINGS "/etc/passwd" userline_apache REGEX "^apache")
|
||||
file(STRINGS "/etc/passwd" userline_www REGEX "^www")
|
||||
if(NOT (userline_apache STREQUAL ""))
|
||||
execute_process(COMMAND echo ${userline_apache} COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(
|
||||
COMMAND echo ${userline_apache}
|
||||
COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
elseif(NOT (userline_www STREQUAL ""))
|
||||
execute_process(COMMAND echo ${userline_www} COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(
|
||||
COMMAND echo ${userline_www}
|
||||
COMMAND cut -d: -f1 OUTPUT_VARIABLE ZM_WEB_USER
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif(NOT (userline_apache STREQUAL ""))
|
||||
message(STATUS "Detected web server user: ${ZM_WEB_USER}")
|
||||
endif(ZM_WEB_USER STREQUAL "")
|
||||
|
@ -561,7 +672,8 @@ message(STATUS "Using web group: ${ZM_WEB_GROUP}")
|
|||
# Check for polkit
|
||||
find_package(Polkit)
|
||||
if(NOT POLKIT_FOUND)
|
||||
message(FATAL_ERROR "Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
|
||||
message(FATAL_ERROR
|
||||
"Running ZoneMinder requires polkit. Building ZoneMinder requires the polkit development package.")
|
||||
endif(NOT POLKIT_FOUND)
|
||||
|
||||
# Some variables that zm expects
|
||||
|
@ -577,7 +689,11 @@ set(CGI_PREFIX "${ZM_CGIDIR}")
|
|||
set(WEB_USER "${ZM_WEB_USER}")
|
||||
set(WEB_GROUP "${ZM_WEB_GROUP}")
|
||||
set(ZM_DB_TYPE "mysql")
|
||||
set(EXTRA_PERL_LIB "use lib '${ZM_PERL_USE_PATH}';")
|
||||
if(ZM_PERL_SEARCH_PATH)
|
||||
set(EXTRA_PERL_LIB "use lib '${ZM_PERL_SEARCH_PATH}'; # Include custom perl install path")
|
||||
else(ZM_PERL_SEARCH_PATH)
|
||||
set(EXTRA_PERL_LIB "# Include from system perl paths only")
|
||||
endif(ZM_PERL_SEARCH_PATH)
|
||||
|
||||
# Generate files from the .in files
|
||||
configure_file(zm.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" @ONLY)
|
||||
|
@ -593,9 +709,9 @@ add_subdirectory(web)
|
|||
add_subdirectory(misc)
|
||||
|
||||
# Enable ONVIF support
|
||||
if (ZM_ONVIF)
|
||||
if(ZM_ONVIF)
|
||||
add_subdirectory(onvif)
|
||||
endif (ZM_ONVIF)
|
||||
endif(ZM_ONVIF)
|
||||
|
||||
# Process distro subdirectories
|
||||
if((ZM_TARGET_DISTRO STREQUAL "f21") OR (ZM_TARGET_DISTRO STREQUAL "f20"))
|
||||
|
@ -614,9 +730,11 @@ message(STATUS "Optional libraries not found:${optlibsnotfound}")
|
|||
message(STATUS "Running ZoneMinder configuration generator")
|
||||
execute_process(COMMAND perl ./zmconfgen.pl RESULT_VARIABLE zmconfgen_result)
|
||||
if(zmconfgen_result EQUAL 0)
|
||||
message(STATUS "ZoneMinder configuration generator completed successfully")
|
||||
message(STATUS
|
||||
"ZoneMinder configuration generator completed successfully")
|
||||
else(zmconfgen_result EQUAL 0)
|
||||
message(FATAL_ERROR "ZoneMinder configuration generator failed. Exit code: ${zmconfgen_result}")
|
||||
message(FATAL_ERROR
|
||||
"ZoneMinder configuration generator failed. Exit code: ${zmconfgen_result}")
|
||||
endif(zmconfgen_result EQUAL 0)
|
||||
|
||||
# Install zm.conf
|
||||
|
|
20
INSTALL
20
INSTALL
|
@ -53,8 +53,8 @@ Advanced:
|
|||
ZM_NO_MMAP Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF
|
||||
ZM_NO_FFMPEG Set to ON to skip ffmpeg checks and force building ZM without ffmpeg. default: OFF
|
||||
ZM_NO_X10 Set to ON to build ZoneMinder without X10 support. default: OFF
|
||||
ZM_PERL_SUBPREFIX Use a different directory for the zm perl modules. NOTE: This is a subprefix, e.g. /lib will be turned into <prefix>/lib, default: <libarch>/perl5
|
||||
ZM_PERL_USE_PATH Override the include path for zm perl modules. Useful if you are moving the perl modules without using the ZM_PERL_SUBPREFIX option. default: <prefix>/<zmperlsubprefix>
|
||||
ZM_PERL_MM_PARMS By default, ZoneMinder's Perl modules are installed into the Vendor folders, as defined by your installation of Perl. You can change that here. Consult Perl's MakeMaker documentation for a definition of acceptable parameters. If you set this to something that causes the modules to be installed outside Perl's normal serach path, then you will also need to set ZM_PERL_SEARCH_PATH accordingly. default: "INSTALLDIRS=vendor NO_PACKLIST=1 NO_PERLLOCAL=1"
|
||||
ZM_PERL_SEARCH_PATH Use to add a folder to your Perl's search path. This will need to be set in cases where ZM_PERL_MM_PARMS has been modified such that ZoneMinder's Perl modules are installed outside Perl's default search path. default: ""
|
||||
|
||||
Useful configuration options provided by cmake:
|
||||
CMAKE_VERBOSE_MAKEFILE - Set this to ON (default OFF) to see what cmake is doing. Very useful for troubleshooting.
|
||||
|
@ -93,9 +93,19 @@ NOTE: The database server, database name, user and password can be different and
|
|||
|
||||
8) Create an apache virtual host for ZoneMinder. Make sure to use the same paths as ZM_WEBDIR and ZM_CGIDIR in /etc/zm.conf
|
||||
9) Create other config if desired (e.g. rsyslog, logrotate and such). Some of this can be found in <prefix>/share/zoneminder/misc or project/misc directory
|
||||
10) Setup an appropriate startup script for your system. A generic sys v init script is here: /scripts/zm while a generic systemd service file is here: /misc/zoneminder.service
|
||||
You must determine which file to use, verify it is correct, and then copy it to the correct location. Consult your distro's documentation. Note that distros using systemd also
|
||||
require /misc/zoneminder-tmpfiles.conf to be copied into the system's tmpfiles.d folder.
|
||||
10) Setup an appropriate startup script for your system. Two generic startup scripts have been provided, a legacy Sys V Init script and a Systemd service file.
|
||||
|
||||
*Sys V Init Setup*
|
||||
- Copy the sys v init script /scripts/zm from the build folder to /etc/init.
|
||||
- Inspect the contents to make sure they apply to your distro.
|
||||
|
||||
*SystemD Setup*
|
||||
- Copy the zoneminder systemd service file /misc/zoneminder.service from the build folder to the systemd service file location.
|
||||
For Redhat based distros, that folder is /usr/lib/systemd/system.
|
||||
- Inspect the contents to make sure they apply to your distro.
|
||||
- Tell systemd to load the new service file: "sudo systemctl daemon-reload".
|
||||
- Copy /misc/zoneminder-tmpfiles.conf to /etc/tmpfiles.d
|
||||
- Tell systemd to process this file: "sudo /usr/bin/systemd-tmpfiles --create /etc/tmpfiles.d/zoneminder.conf".
|
||||
|
||||
Basic steps for upgrading ZoneMinder
|
||||
------------------------------------
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# And these to the user and group of your webserver
|
||||
webuser = @WEB_USER@
|
||||
|
|
182
README.md
182
README.md
|
@ -12,13 +12,46 @@ All documentation for ZoneMinder is now online at http://www.zoneminder.com/wiki
|
|||
|
||||
ZoneMinder is an integrated set of applications which provide a complete surveillance solution allowing capture, analysis, recording and monitoring of any CCTV or security cameras attached to a Linux based machine. It is designed to run on distributions which support the Video For Linux (V4L) interface and has been tested with video cameras attached to BTTV cards, various USB cameras and also supports most IP network cameras.
|
||||
|
||||
## Requirements
|
||||
## Installation Methods
|
||||
|
||||
If you are installing ZoneMinder from a package, that package should provide all of the needed core components.
|
||||
### Building from Source is Discouraged
|
||||
|
||||
### Packages
|
||||
Historically, installing ZoneMinder onto your system required building from source code by issuing the traditional configure, make, make install commands. To get ZoneMinder to build, all of its dependencies had to be determined and installed beforehand. Init and logrotate scripts had to be manually copied into place following the build. Optional packages such as jscalendar and Cambozola had to be manually installed. Uninstalls could leave stale files around, which could cause problems during an upgrade. Speaking of upgrades, when it comes time to upgrade all these manual steps must be repeated again.
|
||||
|
||||
If you are compiling ZoneMinder from source, the below list contains the packages needed to get ZoneMinder built:
|
||||
Better methods exist today that do much of this for you. The current development team, along with other volunteers, have taken great strides in providing the resources necessary to avoid building from source.
|
||||
|
||||
### Install from a Package Repository
|
||||
|
||||
This is the recommended method to install ZoneMinder onto your system. ZoneMinder packages are maintained for the following distros:
|
||||
|
||||
- Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder)
|
||||
- Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder)
|
||||
- RHEL/CentOS and clones via [zmrepo](http://zmrepo.zoneminder.com/)
|
||||
- Fedora via [zmrepo](http://zmrepo.zoneminder.com/)
|
||||
- OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE)
|
||||
- Maegia from their default repository
|
||||
|
||||
If a repository that hosts ZoneMinder packages is not available for your distro, then you are encouraged to build your own package, rather than build from source. While each distro is different in ways that set it apart from all the others, they are often similar enough to allow you to adapt another distro's package building instructions to your own.
|
||||
|
||||
### Building a ZoneMinder Package
|
||||
|
||||
Building ZoneMinder into a package is not any harder than building from source. As a matter of fact, if you have successfully built ZoneMinder from source in the past, then you may find these steps to be easier.
|
||||
|
||||
When building a package, it is best to do this work in a separate environment, dedicated to development purposes. This could be as simple as creating a virtual machine, using Docker, or using mock. All it takes is one “Oops” to regret doing this work on your production server.
|
||||
|
||||
Lastly, if you desire to build a development snapshot from the master branch, it is recommended you first build your package using an official release of ZoneMinder. This will help identify whether any problems you may encounter are caused by the build process or is a new issue in the master branch.
|
||||
|
||||
What follows are instructions for various distros to build ZoneMinder into a package.
|
||||
|
||||
### Package Maintainters
|
||||
Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source.
|
||||
|
||||
For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script:
|
||||
```bash
|
||||
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
|
||||
```
|
||||
|
||||
Note that zmeditconfigdata.sh is intended to be called, from the root build folder, prior to running cmake or configure.
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
|
@ -104,42 +137,118 @@ root@host:~# aptitude install -y gdebi;
|
|||
root@host:~# gdebi /root/zoneminder_1.26.4-1_amd64.deb;
|
||||
```
|
||||
|
||||
#### CentOS / RHEL
|
||||
#### Fedora / CentOS / RHEL
|
||||
|
||||
Additional repositories must be added before one can build zoneminder on CentOS or RHEL:
|
||||
***DRAFT* ** Needs Testing
|
||||
|
||||
1. Zmrepo [ZoneMinder WiKi](http://www.zoneminder.com/wiki/index.php/CentOS#Zmrepo_-_A_ZoneMinder_repository_for_RPM_based_distros)
|
||||
2. EPEL https://fedoraproject.org/wiki/EPEL
|
||||
3. RPMFusion: http://rpmfusion.org/
|
||||
##### Background
|
||||
The following method documents how to build ZoneMinder into an RPM package, compatible with Fedora, Redhat, CentOS, and other compatible clones. This is exactly how the RPMS in zmrepo are built.
|
||||
|
||||
When adding third party repositories, it is highly recommended that the user also install and configure yum priorities as documented in the [CentOS WiKi](http://wiki.centos.org/PackageManagement/Yum/Priorities)
|
||||
The method documented below was chosen because:
|
||||
- All of ZoneMinder's dependencies are downloaded and installed automatically
|
||||
- Cross platform capable. The build host does not have to be the same distro or release version as the target.
|
||||
- Once your build environment is set up, few steps are required to run the build again in the future.
|
||||
- Troubleshooting becomes easier if we are all building ZoneMinder the same way.
|
||||
|
||||
Prioritize the repositories:
|
||||
The build instructions below make use of a custom script called "buildzm.sh". Advanced users are encouraged to view the contents of this script. Notice that the script doesn't really do a whole lot. The goal of the script is to simply make the process a little easier for the first time user. Once you become familar with the build process, you can issue the mock commands found in the buildzm.sh script yourself if you so desire.
|
||||
|
||||
1. Base
|
||||
2. EPEL
|
||||
3. RPMFusion
|
||||
4. Zmrepo
|
||||
***IMPORTANT***
|
||||
Certain commands in these instructions require root privileges while other commands do not. Pay close attention to this. If the instructions below state to issue a command without a “sudo” prefix, then you should *not* be root while issuing the command. Getting this incorrect will result in a failed build.
|
||||
|
||||
Once your repos are in order, install the following:
|
||||
```bash
|
||||
sudo yum install cmake bzip2-devel ffmpeg ffmpeg-devel gnutls-devel httpd libjpeg-turbo libjpeg-turbo-devel mysql-devel mysql-server pcre-devel \
|
||||
perl-Archive-Tar perl-Archive-Zip perl-Convert-BinHex perl-Date-Manip perl-DBD-MySQL perl-DBI perl-Device-SerialPort perl-Email-Date-Format perl-IO-stringy \
|
||||
perl-IO-Zlib perl-MailTools perl-MIME-Lite perl-MIME-tools perl-MIME-Types perl-Module-Load perl-Package-Constants perl-Sys-Mmap perl-Time-HiRes \
|
||||
perl-TimeDate perl-YAML-Syck perl-X10 perl-URI-Encode php php-cli php-mysql x264 vlc-devel vlc-core \
|
||||
libcurl libcurl-devel polkit-devel git
|
||||
##### Set Up Your Environment
|
||||
Before you begin, set up an rpmbuild environment by following [this guide](http://wiki.centos.org/HowTos/SetupRpmBuildEnvironment) by the CentOS developers.
|
||||
|
||||
Next, navigate to [Zmrepo](http://zmrepo.zoneminder.com/), and follow the instructions to enable zmrepo on your system.
|
||||
|
||||
With zmrepo enabled, issue the following command:
|
||||
````bash
|
||||
sudo yum install zmrepo-mock-configs mock
|
||||
```
|
||||
|
||||
To build from the master branch:
|
||||
Add your user account to the group mock:
|
||||
```bash
|
||||
git clone https://github.com/ZoneMinder/ZoneMinder.git
|
||||
cd ZoneMinder
|
||||
cmake .
|
||||
make
|
||||
sudo make install
|
||||
sudo gpasswd -a {your account name} mock
|
||||
```
|
||||
|
||||
IMPORTANT: Don't forget the trailing "." when calling cmake
|
||||
Your build environment is now set up.
|
||||
|
||||
##### Build from SRPM
|
||||
To continue, you need a ZoneMinder SRPM. For starters, let's use one of the SRPMS from zmrepo. Go browse the [Zmrepo](http://zmrepo.zoneminder.com/) site and choose an appropriate SRPM and place it into the ~/rpmbuild/SRPMS folder.
|
||||
|
||||
For CentOS 7, I have chosen the following SRPM:
|
||||
```bash
|
||||
wget -P ~/rpmbuild/SRPMS http://zmrepo.zoneminder.com/el/7/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm
|
||||
```
|
||||
|
||||
Now comes the fun part. To build ZoneMinder, issue the following command:
|
||||
```bash
|
||||
buildzm.sh zmrepo-el7-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm
|
||||
```
|
||||
|
||||
Want to build ZoneMinder for Fedora, instead of CentOS, from the same host? Once you download the Fedora SRPM, issue the following:
|
||||
```bash
|
||||
buildzm.sh zmrepo-f21-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-1.fc21.src.rpm
|
||||
```
|
||||
Notice that the buildzm.sh tool requires the following parameters:
|
||||
```bash
|
||||
buildzm.sh MOCKCONFIG ZONEMINDER_SRPM
|
||||
```
|
||||
The list of available Mock config files are available here:
|
||||
```bash
|
||||
ls /etc/mock/zmrepo*.cfg
|
||||
```
|
||||
|
||||
You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). Notice that, when specifying the Mock config as a commandline parameter, you should leave off the ".cfg" filename extension.
|
||||
|
||||
##### Installation
|
||||
Once the build completes, you will be presented with a folder containing the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo per the instruction on the [Zmrepo](http://zmrepo.zoneminder.com/) website, and then install the rpm by issuing the appropriate yum install command. Finish the installation by following the zoneminder setup instructions in the distro specific readme file, named README.{distroname}, which will be installed into the /usr/share/doc/zoneminder* folder.
|
||||
|
||||
Finally, you may want to consider editing the zmrepo repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo.
|
||||
|
||||
##### How to Modify the Source Prior to Build
|
||||
** UNFINISHED **
|
||||
|
||||
Before attempting this part of the instructions, make sure and follow the previous instructions for building one of the unmodified SRPMS from zmrepo. Knowing this part works will assist in troubleshooting should something go wrong.
|
||||
|
||||
These instructions may vary depending on what exactly you want to do. The following example assumes you want to build a development snapshot from the master branch.
|
||||
|
||||
From the previous instructions, we downloaded a CentOS 7 ZoneMinder SRPM and placed it into ~/rpmbuild/SRPMS. For this example, install it onto your system:
|
||||
```bash
|
||||
rpm -Uvh ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm
|
||||
```
|
||||
|
||||
IMPORTANT: This operation must be done with your normal user account. Do *not* perform this command as root.
|
||||
|
||||
Make sure you have git installed:
|
||||
```bash
|
||||
sudo yum install git
|
||||
```
|
||||
|
||||
Now clone the ZoneMinder git repository:
|
||||
```bash
|
||||
git clone https://github.com/ZoneMinder/ZoneMinder
|
||||
```
|
||||
This will create a sub-folder called ZoneMinder, which will contain the latest developement.
|
||||
|
||||
We want to turn this into a tarball, but first we need to figure out what to name it. Look here:
|
||||
```bash
|
||||
ls ~/rpmbuild/SOURCES
|
||||
```
|
||||
The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From one folder above the local ZoneMinder git repository, execute the following:
|
||||
```bash
|
||||
mv ZoneMinder ZoneMinder-1.28.1
|
||||
tar -cvzf ~/rpmbuild/SOURCES/ZoneMinder-1.28.1.tar.gz ZoneMinder-1.28.1/*
|
||||
```
|
||||
The trailing "/*" leaves off the hidden dot "." file and folders from the git repo, which is what we want.
|
||||
Note that we are overwriting the original tarball. If you wish to keep the original tarball then create a copy prior to creating the new tarball.
|
||||
|
||||
Now build a new src.rpm:
|
||||
```bash
|
||||
rpmbuild -bs --nodeps ~/rpmbuild/SPECS/zoneminder.el7.spec
|
||||
```
|
||||
This step will overwrite the SRPM you originally downloaded, so you may want to back it up prior to completing this step. Note that the name of the specfile will vary slightly depending on what distro you are building for.
|
||||
|
||||
You should now have a a new SRPM under ~/rpmbuild/SRPMS. In our example, the SRPM is called zoneminder-1.28.1-2.el7.centos.src.rpm. Now follow the previous instructions that describe how to use the buildzm script, using ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm as the path to your SRPM.
|
||||
|
||||
#### Docker
|
||||
|
||||
|
@ -147,11 +256,6 @@ Docker is a system to run applications inside isolated containers. ZoneMinder, a
|
|||
Dockerfile contained in this repository. However, there is still work needed to ensure that the main ZM features work
|
||||
properly and are documented.
|
||||
|
||||
### ffmpeg
|
||||
|
||||
This release of ZoneMinder has been tested on and works with ffmpeg version N-55540-g93f4277.
|
||||
|
||||
|
||||
## Contribution Model and Development
|
||||
|
||||
* Source hosted at [GitHub](https://github.com/ZoneMinder/ZoneMinder/)
|
||||
|
@ -172,14 +276,4 @@ the following steps.
|
|||
6. Create new Pull Request
|
||||
7. The team will then review, discuss and hopefully merge your changes.
|
||||
|
||||
### Package Maintainters
|
||||
Many of the ZoneMinder configration variable default values are not configurable at build time through autotools or cmake. A new tool called *zmeditconfigdata.sh* has been added to allow package maintainers to manipulate any variable stored in ConfigData.pm without patching the source.
|
||||
|
||||
For example, let's say I have created a new ZoneMinder package that contains the cambolzola javascript file. However, by default cambozola support is turned off. To fix that, add this to the pacakging script:
|
||||
```bash
|
||||
./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes
|
||||
```
|
||||
|
||||
Note that zmeditconfigdata.sh is intended to be called, from the root build folder, prior to running cmake or configure.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-15147273-6/ZoneMinder/README.md)](https://github.com/igrigorik/ga-beacon)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
aclocal
|
||||
aclocal -I m4
|
||||
autoheader
|
||||
automake --add-missing
|
||||
autoconf
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
# Check whether sendfile() is supported and what prototype it has
|
||||
include(CheckCSourceCompiles)
|
||||
if (UNIX OR MINGW)
|
||||
SET(CMAKE_REQUIRED_DEFINITIONS -Werror-implicit-function-declaration)
|
||||
endif()
|
||||
check_c_source_compiles("#include <sys/sendfile.h>
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
sendfile(1, 1, NULL, 0);
|
||||
return 0;
|
||||
}" HAVE_SENDFILE4_SUPPORT)
|
||||
if(HAVE_SENDFILE4_SUPPORT)
|
||||
add_definitions(-DHAVE_SENDFILE4_SUPPORT=1)
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
message(STATUS "Sendfile support: Linux/Solaris sendfile()")
|
||||
return()
|
||||
endif()
|
||||
find_library(SENDFILE_LIBRARIES NAMES sendfile)
|
||||
if(SENDFILE_LIBRARIES)
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists(sendfile sendfile ${SENDFILE_LIBRARIES} HAVE_SENDFILE4_SUPPORT)
|
||||
if(HAVE_SENDFILE4_SUPPORT)
|
||||
add_definitions(-DHAVE_SENDFILE4_SUPPORT=1)
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
message(STATUS "Sendfile support: Solaris sendfile()")
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
set(SENDFILE_LIBRARIES "")
|
||||
check_c_source_compiles("#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
int main()
|
||||
{
|
||||
sendfile(1, 1, 0, 0, NULL, NULL, 0);
|
||||
return 0;
|
||||
}" HAVE_SENDFILE7_SUPPORT)
|
||||
if(HAVE_SENDFILE7_SUPPORT)
|
||||
add_definitions(-DHAVE_SENDFILE7_SUPPORT=1)
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
message(STATUS "Sendfile support: FreeBSD sendfile()")
|
||||
return()
|
||||
endif()
|
||||
check_c_source_compiles("#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/uio.h>
|
||||
int main()
|
||||
{
|
||||
sendfile(1, 1, 0, NULL, NULL, 0);
|
||||
return 0;
|
||||
}" HAVE_SENDFILE6_SUPPORT)
|
||||
if(HAVE_SENDFILE6_SUPPORT)
|
||||
add_definitions(-DHAVE_SENDFILE6_SUPPORT=1)
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
message(STATUS "Sendfile support: MacOS sendfile()")
|
||||
return()
|
||||
endif()
|
||||
|
42
configure.ac
42
configure.ac
|
@ -3,6 +3,7 @@ AC_INIT(zm,1.28.1,[http://www.zoneminder.com/forums/ - Please check FAQ first],z
|
|||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_SRCDIR(src/zm.h)
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_SUBST([AM_CXXFLAGS], [-D__STDC_CONSTANT_MACROS])
|
||||
|
||||
|
@ -26,6 +27,17 @@ case $host_os in
|
|||
*BSD*)
|
||||
# Do something specific for BSD
|
||||
HOST_OS='BSD'
|
||||
AC_DEFINE(BSD,1,"This is a BSD system")
|
||||
;;
|
||||
*bsd*)
|
||||
# Do something specific for BSD
|
||||
HOST_OS='BSD'
|
||||
AC_DEFINE(BSD,1,"This is a BSD system")
|
||||
;;
|
||||
*solaris*)
|
||||
# Do something specific for Solaris
|
||||
HOST_OS='solaris'
|
||||
AC_DEFINE(SOLARIS,1,"We are running a Solaroid OS [tested on OmniOS]")
|
||||
;;
|
||||
*)
|
||||
#Default Case
|
||||
|
@ -315,22 +327,20 @@ AC_FUNC_STRTOD
|
|||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap posix_memalign putenv select sendfile socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strspn strstr strtol strtoull])
|
||||
AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction])
|
||||
|
||||
# this is required for freebsd to compile. Look for it in m4/ac_check_sendfile.m4
|
||||
AC_CHECK_SENDFILE
|
||||
# Other programs
|
||||
AC_CHECK_PROG(OPT_FFMPEG,ffmpeg,yes,no)
|
||||
AC_PATH_PROG(PATH_FFMPEG,ffmpeg)
|
||||
AC_CHECK_PROG(OPT_NETPBM,pnmscale,yes,no)
|
||||
AC_PATH_PROG(PATH_NETPBM,pnmscale)
|
||||
if test "$OPT_NETPBM" == "yes"; then
|
||||
PATH_NETPBM=`dirname $PATH_NETPBM`
|
||||
fi
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(rt,clock_gettime,,AC_MSG_ERROR(zm requires librt))
|
||||
AC_SEARCH_LIBS(mysql_init,[mysqlclient mariadbclient],,AC_MSG_ERROR(zm requires libmysqlclient.a or libmariadbclient.a))
|
||||
AC_CHECK_LIB(jpeg,jpeg_start_compress,,AC_MSG_ERROR(zm requires libjpeg.a))
|
||||
AC_CHECK_LIB(pthread,pthread_create,,AC_MSG_ERROR(zm requires libpthread.a))
|
||||
if test "$BSD" == "0"; then
|
||||
AC_CHECK_LIB(dl,dlsym,,AC_MSG_ERROR(zm requires libdl.a))
|
||||
fi
|
||||
if test "$ZM_SSL_LIB" == "openssl"; then
|
||||
AC_CHECK_HEADERS(openssl/md5.h,,AC_MSG_WARN(zm requires openssl/md5.h header to be installed for openssl),)
|
||||
AC_CHECK_LIB(crypto,MD5,,AC_MSG_WARN([libcrypto.a is required for authenticated streaming - use ZM_SSL_LIB option to select gnutls instead]))
|
||||
|
@ -374,14 +384,26 @@ AC_CHECK_HEADERS(execinfo.h,,,)
|
|||
AC_CHECK_HEADERS(ucontext.h,,,)
|
||||
AC_CHECK_HEADERS(sys/syscall.h,,,)
|
||||
AC_CHECK_HEADERS(pthread.h,,,)
|
||||
AC_CHECK_HEADERS(linux/videodev.h,AC_SUBST(ZM_HAS_V4L1,1),AC_SUBST(ZM_HAS_V4L1,0),)
|
||||
AC_CHECK_HEADERS(linux/videodev2.h,AC_SUBST(ZM_HAS_V4L2,1),AC_SUBST(ZM_HAS_V4L2,0),)
|
||||
|
||||
# Check for Video for Linux 1 Header Files
|
||||
ZM_HAS_V4L1=0
|
||||
AC_CHECK_HEADERS([libv4l1-videodev.h linux/videodev.h],[ZM_HAS_V4L1=1; break;],,)
|
||||
AC_SUBST(ZM_HAS_V4L1)
|
||||
|
||||
# Check for Video for Linux 2 Header Files
|
||||
ZM_HAS_V4L2=0
|
||||
AC_CHECK_HEADERS(linux/videodev2.h,ZM_HAS_V4L2=1,,)
|
||||
AC_SUBST(ZM_HAS_V4L2)
|
||||
|
||||
# Set global Video for Linux flag
|
||||
ZM_HAS_V4L=0
|
||||
if test "$ZM_HAS_V4L1" == "1" || test "$ZM_HAS_V4L2" == "1"; then
|
||||
AC_SUBST(ZM_HAS_V4L,1)
|
||||
ZM_HAS_V4L=1
|
||||
else
|
||||
AC_SUBST(ZM_HAS_V4L,0)
|
||||
AC_MSG_WARN(zm requires Video4Linux or Video4Linux2 to be installed for analog or USB camera support)
|
||||
fi
|
||||
AC_SUBST(ZM_HAS_V4L)
|
||||
|
||||
AC_CHECK_HEADERS(jpeglib.h,,AC_MSG_ERROR(zm requires libjpeg headers to be installed),)
|
||||
AC_CHECK_HEADERS(mysql/mysql.h,,AC_MSG_ERROR(zm requires MySQL headers - check that MySQL development packages are installed),)
|
||||
AC_LANG_PUSH([C])
|
||||
|
|
|
@ -108,4 +108,9 @@ SELECT * FROM (SELECT NULL as Id,
|
|||
WHERE NOT EXISTS (
|
||||
SELECT Name FROM Controls WHERE name = 'ONVIF Camera'
|
||||
) LIMIT 1;
|
||||
--
|
||||
-- Hide USE_DEEP_STORAGE from user to prevent accidental event loss
|
||||
--
|
||||
UPDATE `zm`.`Config` SET `Category`='hidden' WHERE `Name`='ZM_USE_DEEP_STORAGE';
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ override_dh_auto_configure:
|
|||
-DZM_CGIDIR=/usr/lib/cgi-bin \
|
||||
-DZM_WEB_USER=www-data \
|
||||
-DZM_WEB_GROUP=www-data \
|
||||
-DZM_PERL_SUBPREFIX=/share/perl5 \
|
||||
-DCMAKE_INSTALL_SYSCONFDIR=etc/zm
|
||||
|
||||
override_dh_auto_install:
|
||||
|
|
|
@ -32,7 +32,7 @@ install(CODE "execute_process(COMMAND ln -sf ../../java/cambozola.jar \"\$ENV{DE
|
|||
# Install auxillary files required to run zoneminder on Fedora
|
||||
install(FILES zoneminder.conf DESTINATION /etc/httpd/conf.d PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
install(FILES zoneminder.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
install(FILES zoneminder.tmpfiles DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
install(FILES redalert.wav DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/sounds PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@ too much degradation of performance.
|
|||
%build
|
||||
%cmake \
|
||||
-DZM_TARGET_DISTRO="f19" \
|
||||
-DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \
|
||||
%{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \
|
||||
%{?_without_x10:-DZM_NO_X10=ON} \
|
||||
.
|
||||
|
|
|
@ -31,7 +31,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite)
|
|||
BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap)
|
||||
BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign)
|
||||
BuildRequires: perl(Expect) perl(Sys::Syslog)
|
||||
BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel
|
||||
BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel
|
||||
%{!?_without_ffmpeg:BuildRequires: ffmpeg-devel}
|
||||
%{!?_without_x10:BuildRequires: perl(X10::ActiveHome) perl(Astro::SunTime)}
|
||||
# cmake needs the following installed at build time due to the way it auto-detects certain parameters
|
||||
|
@ -76,7 +76,6 @@ too much degradation of performance.
|
|||
%build
|
||||
%cmake \
|
||||
-DZM_TARGET_DISTRO="f20" \
|
||||
-DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \
|
||||
%{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \
|
||||
%{?_without_x10:-DZM_NO_X10=ON} \
|
||||
.
|
||||
|
|
|
@ -31,7 +31,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite)
|
|||
BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap)
|
||||
BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign)
|
||||
BuildRequires: perl(Expect) perl(Sys::Syslog)
|
||||
BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel
|
||||
BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel
|
||||
%{!?_without_ffmpeg:BuildRequires: ffmpeg-devel}
|
||||
%{!?_without_x10:BuildRequires: perl(X10::ActiveHome) perl(Astro::SunTime)}
|
||||
# cmake needs the following installed at build time due to the way it auto-detects certain parameters
|
||||
|
@ -76,7 +76,6 @@ too much degradation of performance.
|
|||
%build
|
||||
%cmake \
|
||||
-DZM_TARGET_DISTRO="f21" \
|
||||
-DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \
|
||||
%{?_without_ffmpeg:-DZM_NO_FFMPEG=ON} \
|
||||
%{?_without_x10:-DZM_NO_X10=ON} \
|
||||
.
|
||||
|
@ -155,8 +154,6 @@ fi
|
|||
%{!?_without_x10:%{_bindir}/zmx10.pl}
|
||||
|
||||
%{perl_vendorlib}/ZoneMinder*
|
||||
%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder*
|
||||
#%{perl_archlib}/ZoneMinder*
|
||||
%{_mandir}/man*/*
|
||||
%dir %{_libexecdir}/zoneminder
|
||||
%{_libexecdir}/zoneminder/cgi-bin
|
||||
|
|
|
@ -58,7 +58,7 @@ if(ZM_TARGET_DISTRO STREQUAL "el7")
|
|||
install(FILES zoneminder.el7.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
install(FILES zoneminder.el7.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
install(FILES zoneminder.service DESTINATION /usr/lib/systemd/system PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
install(FILES zoneminder.tmpfiles DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(FILES ../../misc/zoneminder-tmpfiles.conf DESTINATION /etc/tmpfiles.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
else(ZM_TARGET_DISTRO STREQUAL "el7")
|
||||
install(FILES zoneminder.el6.conf DESTINATION /etc/httpd/conf.d RENAME zoneminder.conf PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
install(FILES zoneminder.el6.logrotate DESTINATION /etc/logrotate.d RENAME zoneminder PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)
|
||||
|
|
|
@ -73,7 +73,7 @@ too much degradation of performance.
|
|||
%build
|
||||
# Have to override CMAKE_INSTALL_LIBDIR for cmake < 2.8.7 due to this bug:
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=795542
|
||||
%cmake -DZM_TARGET_DISTRO="el6" -DCMAKE_INSTALL_LIBDIR:PATH=%{_lib} -DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` .
|
||||
%cmake -DZM_TARGET_DISTRO="el6" -DCMAKE_INSTALL_LIBDIR:PATH=%{_lib} .
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ BuildRequires: perl(MIME::Entity) perl(MIME::Lite)
|
|||
BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap)
|
||||
BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign)
|
||||
BuildRequires: perl(Expect) perl(Sys::Syslog)
|
||||
BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel
|
||||
BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel
|
||||
BuildRequires: ffmpeg ffmpeg-devel perl(X10::ActiveHome) perl(Astro::SunTime)
|
||||
# cmake needs the following installed at build time due to the way it auto-detects certain parameters
|
||||
BuildRequires: httpd polkit-devel
|
||||
|
@ -69,7 +69,6 @@ too much degradation of performance.
|
|||
%build
|
||||
%cmake \
|
||||
-DZM_TARGET_DISTRO="el7" \
|
||||
-DZM_PERL_SUBPREFIX=`x="%{perl_vendorlib}" ; echo ${x#"%{_prefix}"}` \
|
||||
.
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
@ -108,6 +107,8 @@ if [ $1 -eq 0 ] ; then
|
|||
# Package removal, not upgrade
|
||||
/bin/systemctl --no-reload disable zoneminder.service > /dev/null 2>&1 || :
|
||||
/bin/systemctl stop zoneminder.service > /dev/null 2>&1 || :
|
||||
echo -e "\nRemoving ZoneMinder SELinux policy module. Please wait.\n"
|
||||
/usr/sbin/semodule -r local_zoneminder.pp
|
||||
fi
|
||||
|
||||
%postun
|
||||
|
@ -129,7 +130,8 @@ fi
|
|||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%doc AUTHORS COPYING README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc
|
||||
%doc AUTHORS BUGS ChangeLog COPYING LICENSE NEWS README.md distros/redhat/README.Centos7 distros/redhat/jscalendar-doc
|
||||
%doc distros/redhat/cambozola-doc distros/redhat/local_zoneminder.te
|
||||
%config %attr(640,root,%{zmgid_final}) /etc/zm/zm.conf
|
||||
%config(noreplace) %attr(644,root,root) /etc/httpd/conf.d/zoneminder.conf
|
||||
%config(noreplace) /etc/tmpfiles.d/zoneminder.conf
|
||||
|
@ -157,7 +159,8 @@ fi
|
|||
%{_bindir}/zmx10.pl
|
||||
|
||||
%{perl_vendorlib}/ZoneMinder*
|
||||
%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder*
|
||||
%{perl_vendorarch}/auto/ZoneMinder/.packlist
|
||||
#%{perl_vendorlib}/%{_arch}-linux-thread-multi/auto/ZoneMinder*
|
||||
#%{perl_archlib}/ZoneMinder*
|
||||
%{_mandir}/man*/*
|
||||
%dir %{_libexecdir}/zoneminder
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
zoneminder for Debian
|
||||
---------------------
|
||||
|
||||
There is one manual step to get the web interface working.
|
||||
You need to link /etc/zm/apache.conf to /etc/apache2/conf.d/zoneminder.conf,
|
||||
then reload the apache config (i.e. /etc/init.d/apache2 reload)
|
||||
|
||||
Changing the location for images and events
|
||||
-------------------------------------------
|
||||
|
||||
Zoneminder, in its upstream form, stores data in /usr/share/zoneminder/. This
|
||||
package modifies that by changing /usr/share/zoneminder/images and
|
||||
/usr/share/zoneminder/events to symlinks to directories under
|
||||
/var/cache/zoneminder.
|
||||
|
||||
There are numerous places these could be put and ways to do it. But, at the
|
||||
moment, if you change this, an upgrade will fail with a warning about these
|
||||
locations having changed (the reason for this was that previously, an upgrade
|
||||
would silently revert the changes and cause event loss - refer
|
||||
bug #608793).
|
||||
|
||||
If you do want to change the location, here are a couple of suggestions.
|
||||
(thanks to vagrant@freegeek.org):
|
||||
|
||||
These lines in fstab could allow you to bind-mount an alternate location
|
||||
|
||||
/dev/sdX1 /otherdrive ext3 defaults 0 2
|
||||
/otherdrive/zoneminder/images /var/cache/zoneminder/images bind defaults 0 2
|
||||
/otherdrive/zoneminder/events /var/cache/zoneminder/events bind defaults 0 2
|
||||
|
||||
or if you have a separate partition for each:
|
||||
|
||||
/dev/sdX1 /var/cache/zoneminder/images ext3 defaults 0 2
|
||||
/dev/sdX2 /var/cache/zoneminder/events ext3 defaults 0 2
|
||||
|
||||
|
||||
|
||||
-- Peter Howard <pjh@northern-ridge.com.au>, Sun, 16 Jan 2010 01:35:51 +1100
|
||||
|
||||
Access to /dev/video*
|
||||
---------------------
|
||||
|
||||
For cameras which require access to /dev/video*, zoneminder may need the
|
||||
www-data user added to the video group in order to see those cameras:
|
||||
|
||||
adduser www-data video
|
||||
|
||||
Note that all web applications running on the zoneminder server will then have
|
||||
access to all video devices on the system.
|
||||
|
||||
-- Vagrant Cascadian <vagrant@debian.org> Sun, 27 Mar 2011 13:06:56 -0700
|
|
@ -0,0 +1,9 @@
|
|||
Alias /zm /usr/share/zoneminder
|
||||
|
||||
<Directory /usr/share/zoneminder>
|
||||
php_flag register_globals off
|
||||
Options Indexes FollowSymLinks
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.php
|
||||
</IfModule>
|
||||
</Directory>
|
|
@ -0,0 +1,86 @@
|
|||
zoneminder (1.28.1+1-trusty-SNAPSHOT2015030201) trusty; urgency=medium
|
||||
|
||||
* maybe fix for RTSP Basic Auth
|
||||
* Also remove dependency on netpbm
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Mon, 02 Mar 2015 11:25:59 -0500
|
||||
|
||||
zoneminder (1.28.1+1-utopic-SNAPSHOT2015022301) utopic; urgency=medium
|
||||
|
||||
* Big merge of onvif support and some fixes.
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Mon, 23 Feb 2015 19:45:45 -0500
|
||||
|
||||
zoneminder (1.28.0+1-trusty-SNAPSHOT2015021201) trusty; urgency=medium
|
||||
|
||||
* add mysql-client-5.6 as a dependency instaed of mysql-client.
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Fri, 13 Feb 2015 09:35:13 -0500
|
||||
|
||||
zoneminder (1.28.0+1-trusty-SNAPSHOT2015011101) trusty; urgency=medium
|
||||
|
||||
* small changes
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Fri, 12 Dec 2014 16:38:36 -0500
|
||||
|
||||
zoneminder (1.28.0+1-utopic-SNAPSHOT2014112001) utopic; urgency=medium
|
||||
|
||||
* Various fixes and developments since 1.28.0. Includes Digest-Auth for HTTP and better for RTSP
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Thu, 20 Nov 2014 10:57:57 -0500
|
||||
|
||||
zoneminder (1.28.0-trusty) trusty; urgency=medium
|
||||
|
||||
* Release
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Fri, 17 Oct 2014 09:25:55 -0400
|
||||
|
||||
zoneminder (1.27.99+1-trusty-SNAPSHOT2014101401) trusty; urgency=medium
|
||||
|
||||
* Several PR merges in big push for 1.28.0
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Tue, 14 Oct 2014 09:28:29 -0400
|
||||
|
||||
zoneminder (1.27.99+1-trusty-SNAPSHOT2014092601) trusty; urgency=medium
|
||||
|
||||
* style updates and db fixes for database logging filters
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Fri, 26 Sep 2014 14:44:45 -0400
|
||||
|
||||
zoneminder (1.27.99+1-trusty-SNAPSHOT2014090801) trusty; urgency=medium
|
||||
|
||||
* several segfault fixes for local cameras
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Mon, 08 Sep 2014 16:56:57 -0400
|
||||
|
||||
zoneminder (1.27.99+1-trusty-SNAPSHOT2014090701) trusty; urgency=medium
|
||||
|
||||
* Fix segfaults for local cameras, also now includes the systemd support patch
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Sun, 07 Sep 2014 17:19:01 -0400
|
||||
|
||||
zoneminder (1.27.99+1-trusty-SNAPSHOT2014082102) trusty; urgency=medium
|
||||
|
||||
* Fix UI inputs for v4l multibuffer and captures per frame
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Thu, 21 Aug 2014 12:03:31 -0400
|
||||
|
||||
zoneminder (1.27.99+1-trusty-SNAPSHOT2014082101) trusty; urgency=medium
|
||||
|
||||
* fall back to Config table values for V4l MultiBUffer and Captures Per Frame
|
||||
* add mention of monitor page settings for thse in the config table
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Thu, 21 Aug 2014 10:04:46 -0400
|
||||
|
||||
zoneminder (1.27.99+1-precise-SNAPSHOT2014080601) precise; urgency=medium
|
||||
|
||||
* improve error messages
|
||||
* Make zmupdate re-run the most recent patch so that people running the daily builds get their db updates
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Wed, 06 Aug 2014 20:20:20 -0400
|
||||
|
||||
zoneminder (1.27.0+1-trusty-v4ltomonitor-1) trusty; urgency=high
|
||||
|
||||
* Snapshot release -
|
||||
|
||||
-- Isaac Connor <iconnor@connortechnology.com> Wed, 09 Jul 2014 21:35:29 -0400
|
|
@ -0,0 +1 @@
|
|||
9
|
|
@ -0,0 +1,40 @@
|
|||
Source: zoneminder
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Isaac Connor <iconnor@connortechnology.com>
|
||||
Build-Depends: debhelper (>= 9), dh-systemd (>= 1.5), autoconf, automake, quilt, libphp-serialization-perl, libgnutls-dev, libmysqlclient-dev | libmariadbclient-dev, libdbd-mysql-perl, libdate-manip-perl, libwww-perl, libjpeg8-dev|libjpeg9-dev|libjpeg62-turbo-dev, libpcre3-dev, libavcodec-ffmpeg-dev, libavformat-ffmpeg-dev, libswscale-ffmpeg-dev, libavutil-ffmpeg-dev, libv4l-dev (>= 0.8.3), libbz2-dev, libtool, libsys-mmap-perl, ffmpeg, libavdevice-ffmpeg-dev, libdevice-serialport-perl, libpcre3, libarchive-zip-perl, libmime-lite-perl, dh-autoreconf, libvlccore-dev, libvlc-dev, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libgcrypt11-dev, libpolkit-gobject-1-dev
|
||||
Standards-Version: 3.9.4
|
||||
|
||||
Package: zoneminder
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2, libapache2-mod-php5 | libapache2-mod-fcgid, php5, php5-mysql|php5-mysqlnd, libphp-serialization-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl, mariadb-client|mysql-client|mysql-client-5.6, libwww-perl, libarchive-tar-perl, libarchive-zip-perl, libdevice-serialport-perl, libpcre3, ffmpeg, rsyslog | system-log-daemon, libmodule-load-perl, libsys-mmap-perl, libjson-any-perl, libavdevice-ffmpeg56, libjpeg8|libjpeg9|libjpeg62-turbo, zip, libnet-sftp-foreign-perl, libio-pty-perl, libexpect-perl, libvlccore5 | libvlccore7 | libvlccore8, libvlc5, libcurl4-gnutls-dev | libcurl4-nss-dev | libcurl4-openssl-dev, libpolkit-gobject-1-0, liburi-encode-perl
|
||||
Recommends: mysql-server|mariadb-server
|
||||
Description: Video camera security and surveillance solution
|
||||
ZoneMinder is intended for use in single or multi-camera video security
|
||||
applications, including commercial or home CCTV, theft prevention and child
|
||||
or family member or home monitoring and other care scenarios. It
|
||||
supports capture, analysis, recording, and monitoring of video data coming
|
||||
from one or more video or network cameras attached to a Linux system.
|
||||
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
|
||||
cameras using a variety of protocols. It is suitable for use as a home
|
||||
video security system and for commercial or professional video security
|
||||
and surveillance. It can also be integrated into a home automation system
|
||||
via X.10 or other protocols.
|
||||
|
||||
Package: zoneminder-dbg
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Architecture: any
|
||||
Depends: zoneminder (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debugging symbols for zoneminder.
|
||||
ZoneMinder is a video camera security and surveillance solution.
|
||||
ZoneMinder is intended for use in single or multi-camera video security
|
||||
applications, including commercial or home CCTV, theft prevention and child
|
||||
or family member or home monitoring and other care scenarios. It
|
||||
supports capture, analysis, recording, and monitoring of video data coming
|
||||
from one or more video or network cameras attached to a Linux system.
|
||||
ZoneMinder also support web and semi-automatic control of Pan/Tilt/Zoom
|
||||
cameras using a variety of protocols. It is suitable for use as a home
|
||||
video security system and for commercial or professional video security
|
||||
and surveillance. It can also be integrated into a home automation system
|
||||
via X.10 or other protocols.
|
|
@ -0,0 +1,22 @@
|
|||
Copyright:
|
||||
|
||||
Copyright 2002 Philip Coombes <philip.coombes@zoneminder.com>
|
||||
|
||||
License:
|
||||
|
||||
This package 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 package 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 package; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
On Debian GNU/Linux systems, the text of the GPL can be found in
|
||||
/usr/share/common-licenses/GPL.
|
|
@ -0,0 +1,6 @@
|
|||
var/log/zm
|
||||
var/lib/zm
|
||||
var/cache/zoneminder/events
|
||||
var/cache/zoneminder/images
|
||||
var/cache/zoneminder/temp
|
||||
usr/share/zoneminder/db
|
|
@ -0,0 +1 @@
|
|||
README.md
|
|
@ -0,0 +1,12 @@
|
|||
usr/bin
|
||||
usr/lib/cgi-bin
|
||||
usr/share/man
|
||||
usr/share/perl5/ZoneMinder
|
||||
usr/share/perl5/ZoneMinder.pm
|
||||
usr/share/polkit-1/actions
|
||||
usr/share/polkit-1/rules.d
|
||||
usr/share/zoneminder
|
||||
etc/zm
|
||||
db/zm_create.sql usr/share/zoneminder/db
|
||||
db/zm_update-*.sql usr/share/zoneminder/db
|
||||
debian/apache.conf etc/zm
|
|
@ -0,0 +1,4 @@
|
|||
var/cache/zoneminder/events usr/share/zoneminder/events
|
||||
var/cache/zoneminder/images usr/share/zoneminder/images
|
||||
var/cache/zoneminder/temp usr/share/zoneminder/temp
|
||||
usr/lib/cgi-bin usr/share/zoneminder/cgi-bin
|
|
@ -0,0 +1,53 @@
|
|||
#! /bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" = "configure" ]; then
|
||||
if [ -e "/lib/systemd/system/mysql.service" ]; then
|
||||
#
|
||||
# Get mysql started if it isn't
|
||||
#
|
||||
if ! $(systemctl is-active mysql >/dev/null 2>&1); then
|
||||
systemctl start mysql
|
||||
fi
|
||||
if $(systemctl is-active mysql >/dev/null 2>&1); then
|
||||
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f reload
|
||||
# test if database if already present...
|
||||
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||
echo 'grant lock tables, alter,select,insert,update,delete on zm.* to 'zmuser'@localhost identified by "zmpass";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
fi
|
||||
|
||||
systemctl stop zoneminder || true #not sure about "|| true"
|
||||
zmupdate.pl --nointeractive
|
||||
|
||||
else
|
||||
echo 'NOTE: mysql not running, please start mysql and run dpkg-reconfigure zoneminder when it is running.'
|
||||
fi
|
||||
else
|
||||
echo 'mysql not found, assuming remote server.'
|
||||
fi
|
||||
chown www-data:www-data /var/log/zm
|
||||
chown www-data:www-data /var/lib/zm/
|
||||
if [ -z "$2" ]; then
|
||||
chown www-data:www-data -R /var/cache/zoneminder
|
||||
fi
|
||||
fi
|
||||
# Ensure zoneminder is stopped...
|
||||
if [ -e "/lib/systemd/system/zoneminder.service" ]; then #changed from -x to -e, could be wrong
|
||||
if systemctl is-active zoneminder >/dev/null 2>&1 ; then
|
||||
systemctl stop zoneminder || exit $?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$1" = "configure" ]; then
|
||||
if [ -z "$2" ]; then
|
||||
chown www-data:www-data /var/log/zm
|
||||
chown www-data:www-data /var/lib/zm/
|
||||
chown www-data:www-data -R /var/cache/zoneminder
|
||||
else
|
||||
chown www-data:www-data /var/log/zm
|
||||
zmupdate.pl
|
||||
fi
|
||||
fi
|
||||
#DEBHELPER#
|
|
@ -0,0 +1,9 @@
|
|||
#! /bin/sh
|
||||
# set -e # to be reinstated later
|
||||
|
||||
if [ "$1" = "purge" ]; then
|
||||
echo 'delete from user where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
echo 'delete from db where User="zmuser";' | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
mysqladmin --defaults-file=/etc/mysql/debian.cnf -f drop zm
|
||||
fi
|
||||
#DEBHELPER#
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
abort=false
|
||||
if [ -L /usr/share/zoneminder/events ]; then
|
||||
l=$(readlink /usr/share/zoneminder/events)
|
||||
if [ "$l" != "/var/cache/zoneminder/events" ]; then
|
||||
abort=true
|
||||
fi
|
||||
fi
|
||||
if [ -L /usr/share/zoneminder/images ]; then
|
||||
l=$(readlink /usr/share/zoneminder/images )
|
||||
if [ "$l" != "/var/cache/zoneminder/images" ]; then
|
||||
abort=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$abort" = "true" ]; then
|
||||
cat >&2 << EOF
|
||||
Aborting installation of zoneminder due to non-default symlinks in
|
||||
/usr/share/zoneminder for the images and/or events directory, which could
|
||||
result in loss of data. Please move your data in each of these directories to
|
||||
/var/cache/zoneminder before installing zoneminder from the package.
|
||||
EOF
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# These are used for cross-compiling and for saving the configure script
|
||||
# from having to guess our platform (since we know it already)
|
||||
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
|
||||
CFLAGS = -Wall -g
|
||||
CPPFLAGS = -D__STDC_CONSTANT_MACROS
|
||||
CXXFLAGS = -DHAVE_LIBCRYPTO
|
||||
|
||||
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -O0
|
||||
else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
|
||||
%:
|
||||
dh $@ --with quilt,autoreconf,systemd
|
||||
|
||||
override_dh_auto_configure:
|
||||
CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" dh_auto_configure -- --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --sysconfdir=/etc/zm --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-mysql=/usr --with-mariadb=/usr --with-webdir=/usr/share/zoneminder --with-ffmpeg=/usr --with-cgidir=/usr/lib/cgi-bin --with-webuser=www-data --with-webgroup=www-data --enable-crashtrace=no --enable-mmap=yes
|
||||
|
||||
override_dh_clean:
|
||||
# Add here commands to clean up after the build process.
|
||||
[ ! -f Makefile ] || $(MAKE) distclean
|
||||
dh_clean
|
||||
|
||||
override_dh_install:
|
||||
dh_install --fail-missing
|
||||
#
|
||||
# NOTE: This is a short-term kludge; hopefully changes in the next
|
||||
# upstream version will render this unnecessary.
|
||||
rm -rf debian/zoneminder/usr/share/zoneminder/events
|
||||
rm -rf debian/zoneminder/usr/share/zoneminder/images
|
||||
rm -rf debian/zoneminder/usr/share/zoneminder/temp
|
||||
dh_link var/cache/zoneminder/events usr/share/zoneminder/events
|
||||
dh_link var/cache/zoneminder/images usr/share/zoneminder/images
|
||||
dh_link var/cache/zoneminder/temp usr/share/zoneminder/temp
|
||||
|
||||
#
|
||||
# This is a slightly lesser kludge; moving the cgi stuff to
|
||||
# /usr/share/zoneminder/cgi-bin breaks one set of behavior,
|
||||
# having it just in /usr/lib/cgi-bin breaks another bit of
|
||||
# behavior.
|
||||
#
|
||||
dh_link usr/lib/cgi-bin usr/share/zoneminder/cgi-bin
|
||||
|
||||
override_dh_fixperms:
|
||||
dh_fixperms
|
||||
chown root:root debian/zoneminder/etc/zm/zm.conf
|
||||
|
||||
override_dh_auto_test:
|
||||
# do not run tests...
|
||||
|
||||
.PHONY: override_dh_strip
|
||||
override_dh_strip:
|
||||
dh_strip --dbg-package=zoneminder-dbg
|
|
@ -0,0 +1,3 @@
|
|||
version=3
|
||||
http://www.zoneminder.com/downloads.html \
|
||||
.*/ZoneMinder-(.*).tar.gz
|
|
@ -0,0 +1,16 @@
|
|||
# ZoneMinder systemd unit file
|
||||
# This file is intended to work with all Linux distributions
|
||||
[Unit]
|
||||
Description=ZoneMinder CCTV recording and security system
|
||||
After=network.target mysql.service apache2.service
|
||||
Requires=mysql.service apache2.service
|
||||
[Service]
|
||||
User=www-data
|
||||
Type=forking
|
||||
ExecStart=/usr/bin/zmpkg.pl start
|
||||
ExecReload=/usr/bin/zmpkg.pl restart
|
||||
ExecStop=/usr/bin/zmpkg.pl stop
|
||||
PIDFile="/run/zm/zm.pid"
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
d /var/run/zm 0755 www-data www-data
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
AC_DEFUN([AC_CHECK_SENDFILE],[
|
||||
AC_MSG_CHECKING([whether sendfile() is supported and what prototype it has])
|
||||
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror-implicit-function-declaration"
|
||||
ac_sendfile_supported=no
|
||||
AC_TRY_LINK([#include <sys/sendfile.h>
|
||||
#include <stdio.h>],
|
||||
[sendfile(1, 1, NULL, 0);],
|
||||
[
|
||||
AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1,
|
||||
[Define this if Linux/Solaris sendfile() is supported])
|
||||
AC_MSG_RESULT([Linux sendfile()])
|
||||
ac_sendfile_supported=yes
|
||||
], [])
|
||||
|
||||
if test x$ac_sendfile_supported = xno; then
|
||||
dnl Checking wether we need libsendfile
|
||||
dnl Presumably on Solaris
|
||||
AC_CHECK_LIB(sendfile, sendfile,
|
||||
[
|
||||
AC_DEFINE(HAVE_SENDFILE4_SUPPORT, 1,
|
||||
[Define this if Linux/Solaris sendfile() is supported])
|
||||
SENDFILE_LIBS="-lsendfile"
|
||||
AC_SUBST(SENDFILE_LIBS)
|
||||
AC_MSG_RESULT([Solaris sendfile()])
|
||||
ac_sendfile_supported=yes
|
||||
], [])
|
||||
fi
|
||||
|
||||
if test x$ac_sendfile_supported = xno; then
|
||||
dnl Checking wether we have FreeBSD-like sendfile() support.
|
||||
AC_TRY_LINK([#include <sys/socket.h>
|
||||
#include <stdio.h>],
|
||||
[sendfile(1, 1, 0, 0, NULL, NULL, 0);],
|
||||
[
|
||||
AC_DEFINE(HAVE_SENDFILE7_SUPPORT, 1,
|
||||
[Define this if FreeBSD sendfile() is supported])
|
||||
AC_MSG_RESULT([FreeBSD sendfile()])
|
||||
ac_sendfile_supported=yes
|
||||
], [])
|
||||
fi
|
||||
|
||||
if test x$ac_sendfile_supported = xno; then
|
||||
dnl Checking wether we have MacOS-like sendfile() support.
|
||||
AC_TRY_LINK([#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/uio.h>],
|
||||
[sendfile(1, 1, 0, NULL, NULL, 0);],
|
||||
[
|
||||
AC_DEFINE(HAVE_SENDFILE6_SUPPORT, 1,
|
||||
[Define this if MacOS sendfile() is supported])
|
||||
AC_MSG_RESULT([MacOS sendfile()])
|
||||
ac_sendfile_supported=yes
|
||||
], [])
|
||||
fi
|
||||
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
|
||||
if test x$ac_sendfile_supported = xno; then
|
||||
AC_MSG_RESULT([no sendfile() support, using read/send])
|
||||
fi
|
||||
])
|
|
@ -1 +1,4 @@
|
|||
d @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||
D @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||
D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||
D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@
|
||||
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
# CMakeLists.txt for the ZoneMinder ONVIF modules.
|
||||
|
||||
# If this is an out-of-source build, copy the files we need to the binary directory
|
||||
if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE)
|
||||
endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
|
||||
# MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt
|
||||
|
||||
# Add build target for the perl modules
|
||||
add_custom_target(zmonvifmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules")
|
||||
add_custom_target(zmonvifmodules ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module")
|
||||
|
||||
# Add install target for the perl modules
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/")
|
||||
|
||||
# Add additional files and directories to make clean
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl")
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
# CMakeLists.txt for the ZoneMinder ONVIF proxy module.
|
||||
|
||||
# If this is an out-of-source build, copy the files we need to the binary directory
|
||||
if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE)
|
||||
endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
|
||||
# MAKEMAKER_NOECHO_COMMAND previously defined in /scripts/zoneminder/CMakeLists.txt
|
||||
|
||||
# Add build target for the perl modules
|
||||
add_custom_target(zmonvifproxy ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules")
|
||||
add_custom_target(zmonvifproxy ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl ONVIF proxy module")
|
||||
|
||||
# Add install target for the perl modules
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/")
|
||||
|
||||
# Add additional files and directories to make clean
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl")
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
# If this is an out-of-source build, copy the files we need to the binary directory
|
||||
if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Changes" "${CMAKE_CURRENT_BINARY_DIR}/Changes")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.PL")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/MANIFEST" "${CMAKE_CURRENT_BINARY_DIR}/MANIFEST")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/META.yml" "${CMAKE_CURRENT_BINARY_DIR}/META.yml")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/README" "${CMAKE_CURRENT_BINARY_DIR}/README")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/t" "${CMAKE_CURRENT_BINARY_DIR}/t")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/lib" "${CMAKE_CURRENT_BINARY_DIR}/lib")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Changes" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/MANIFEST" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/META.yml" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/README" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/t" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/lib" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE)
|
||||
endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR))
|
||||
|
||||
# Create files from the .in files
|
||||
|
@ -24,10 +24,10 @@ else(CMAKE_VERBOSE_MAKEFILE)
|
|||
endif(CMAKE_VERBOSE_MAKEFILE)
|
||||
|
||||
# Add build target for the perl modules
|
||||
add_custom_target(zmperlmodules ALL perl Makefile.PL FIRST_MAKEFILE=MakefilePerl PREFIX="${CMAKE_CURRENT_BINARY_DIR}/output" LIB="${CMAKE_CURRENT_BINARY_DIR}/output/${ZM_PERL_SUBPREFIX}" INSTALLSITEMAN3DIR="${CMAKE_CURRENT_BINARY_DIR}/output/${CMAKE_INSTALL_MANDIR}/man3" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules")
|
||||
add_custom_target(zmperlmodules ALL perl Makefile.PL ${ZM_PERL_MM_PARMS} FIRST_MAKEFILE=MakefilePerl DESTDIR="${CMAKE_CURRENT_BINARY_DIR}/output" ${MAKEMAKER_NOECHO_COMMAND} COMMAND make --makefile=MakefilePerl pure_install COMMENT "Building ZoneMinder perl modules")
|
||||
|
||||
# Add install target for the perl modules
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/output/" DESTINATION "/")
|
||||
|
||||
# Add additional files and directories to make clean
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "output;blib;pm_to_blib;MakefilePerl")
|
||||
|
|
|
@ -36,34 +36,42 @@ use ZoneMinder::General qw(:all);
|
|||
use ZoneMinder::Database qw(:all);
|
||||
use ZoneMinder::Memory qw(:all);
|
||||
|
||||
our @ISA = qw(Exporter ZoneMinder::Base ZoneMinder::Config ZoneMinder::Logger ZoneMinder::General ZoneMinder::Database ZoneMinder::Memory);
|
||||
our @ISA = qw(
|
||||
Exporter
|
||||
ZoneMinder::Base
|
||||
ZoneMinder::Config
|
||||
ZoneMinder::Logger
|
||||
ZoneMinder::General
|
||||
ZoneMinder::Database
|
||||
ZoneMinder::Memory
|
||||
);
|
||||
|
||||
# Items to export into callers namespace by default. Note: do not export
|
||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'base' => [
|
||||
@ZoneMinder::Base::EXPORT_OK
|
||||
],
|
||||
'config' => [
|
||||
@ZoneMinder::Config::EXPORT_OK
|
||||
],
|
||||
'debug' => [
|
||||
@ZoneMinder::Logger::EXPORT_OK
|
||||
],
|
||||
'general' => [
|
||||
@ZoneMinder::General::EXPORT_OK
|
||||
],
|
||||
'database' => [
|
||||
@ZoneMinder::Database::EXPORT_OK
|
||||
],
|
||||
'memory' => [
|
||||
@ZoneMinder::Memory::EXPORT_OK
|
||||
],
|
||||
'base' => [
|
||||
@ZoneMinder::Base::EXPORT_OK
|
||||
],
|
||||
'config' => [
|
||||
@ZoneMinder::Config::EXPORT_OK
|
||||
],
|
||||
'debug' => [
|
||||
@ZoneMinder::Logger::EXPORT_OK
|
||||
],
|
||||
'general' => [
|
||||
@ZoneMinder::General::EXPORT_OK
|
||||
],
|
||||
'database' => [
|
||||
@ZoneMinder::Database::EXPORT_OK
|
||||
],
|
||||
'memory' => [
|
||||
@ZoneMinder::Memory::EXPORT_OK
|
||||
],
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Base;
|
||||
|
@ -38,7 +38,7 @@ use constant ZM_VERSION => "@VERSION@";
|
|||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = ( 'all' => [ qw(ZM_VERSION) ] );
|
||||
|
@ -62,7 +62,11 @@ ZoneMinder::Base - Base perl module for ZoneMinder
|
|||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module is the base module for the rest of the ZoneMinder modules. It is included by each of the other modules but serves no purpose other than to propagate the perl module version amongst the other modules. You will never need to use this module directly but if you write new ZoneMinder modules they should include it.
|
||||
This module is the base module for the rest of the ZoneMinder modules. It
|
||||
is included by each of the other modules but serves no purpose other than
|
||||
to propagate the perl module version amongst the other modules. You will
|
||||
never need to use this module directly but if you write new ZoneMinder
|
||||
modules they should include it.
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Config;
|
||||
|
@ -38,15 +38,15 @@ use vars qw( %Config );
|
|||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our @EXPORT_CONFIG = qw( %Config ); # Get populated by BEGIN
|
||||
|
||||
our %EXPORT_TAGS = (
|
||||
'constants' => [ qw(
|
||||
ZM_PID
|
||||
) ]
|
||||
'constants' => [ qw(
|
||||
ZM_PID
|
||||
) ]
|
||||
);
|
||||
push( @{$EXPORT_TAGS{config}}, @EXPORT_CONFIG );
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
@ -65,38 +65,43 @@ use Carp;
|
|||
# Load the config from the database into the symbol table
|
||||
BEGIN
|
||||
{
|
||||
my $config_file = ZM_CONFIG;
|
||||
( my $local_config_file = $config_file ) =~ s|^.*/|./|;
|
||||
if ( -s $local_config_file and -r $local_config_file )
|
||||
{
|
||||
print( STDERR "Warning, overriding installed $local_config_file file with local copy\n" );
|
||||
$config_file = $local_config_file;
|
||||
}
|
||||
open( CONFIG, "<".$config_file ) or croak( "Can't open config file '$config_file': $!" );
|
||||
foreach my $str ( <CONFIG> )
|
||||
{
|
||||
next if ( $str =~ /^\s*$/ );
|
||||
next if ( $str =~ /^\s*#/ );
|
||||
my $config_file = ZM_CONFIG;
|
||||
( my $local_config_file = $config_file ) =~ s|^.*/|./|;
|
||||
if ( -s $local_config_file and -r $local_config_file )
|
||||
{
|
||||
print( STDERR "Warning, overriding installed $local_config_file file with local copy\n" );
|
||||
$config_file = $local_config_file;
|
||||
}
|
||||
open( my $CONFIG, "<", $config_file )
|
||||
or croak( "Can't open config file '$config_file': $!" );
|
||||
foreach my $str ( <$CONFIG> )
|
||||
{
|
||||
next if ( $str =~ /^\s*$/ );
|
||||
next if ( $str =~ /^\s*#/ );
|
||||
my ( $name, $value ) = $str =~ /^\s*([^=\s]+)\s*=\s*(.*?)\s*$/;
|
||||
if ( ! $name ) {
|
||||
print( STDERR "Warning, bad line in $config_file: $str\n" );
|
||||
next;
|
||||
} # end if
|
||||
$name =~ tr/a-z/A-Z/;
|
||||
$Config{$name} = $value;
|
||||
}
|
||||
close( CONFIG );
|
||||
if ( ! $name ) {
|
||||
print( STDERR "Warning, bad line in $config_file: $str\n" );
|
||||
next;
|
||||
} # end if
|
||||
$name =~ tr/a-z/A-Z/;
|
||||
$Config{$name} = $value;
|
||||
}
|
||||
close( $CONFIG );
|
||||
|
||||
use DBI;
|
||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} ) or croak( "Can't connect to db" );
|
||||
my $sql = 'select * from Config';
|
||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
||||
while( my $config = $sth->fetchrow_hashref() ) {
|
||||
$Config{$config->{Name}} = $config->{Value};
|
||||
}
|
||||
$sth->finish();
|
||||
#$dbh->disconnect();
|
||||
use DBI;
|
||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.";host=".$Config{ZM_DB_HOST}
|
||||
, $Config{ZM_DB_USER}
|
||||
, $Config{ZM_DB_PASS}
|
||||
) or croak( "Can't connect to db" );
|
||||
my $sql = 'select * from Config';
|
||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
||||
while( my $config = $sth->fetchrow_hashref() ) {
|
||||
$Config{$config->{Name}} = $config->{Value};
|
||||
}
|
||||
$sth->finish();
|
||||
#$dbh->disconnect();
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -112,9 +117,16 @@ ZoneMinder::Config - ZoneMinder configuration module.
|
|||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The ZoneMinder::Config module is used to import the ZoneMinder configuration from the database. It will do this at compile time in a BEGIN block and require access to the zm.conf file either in the current directory or in its defined location in order to determine database access details, configuration from this file will also be included. If the :all or :config tags are used then this configuration is exported into the namespace of the calling program or module.
|
||||
The ZoneMinder::Config module is used to import the ZoneMinder
|
||||
configuration from the database. It will do this at compile time in a BEGIN
|
||||
block and require access to the zm.conf file either in the current
|
||||
directory or in its defined location in order to determine database access
|
||||
details, configuration from this file will also be included. If the :all or
|
||||
:config tags are used then this configuration is exported into the
|
||||
namespace of the calling program or module.
|
||||
|
||||
Once the configuration has been imported then configuration variables are defined as constants and can be accessed directory by name, e.g.
|
||||
Once the configuration has been imported then configuration variables are
|
||||
defined as constants and can be accessed directory by name, e.g.
|
||||
|
||||
$lang = $Config{ZM_LANG_DEFAULT};
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the debug definitions and functions used by the rest
|
||||
# This module contains the debug definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::ConfigAdmin;
|
||||
|
@ -37,14 +37,14 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
|||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
loadConfigFromDB
|
||||
saveConfigToDB
|
||||
) ]
|
||||
'functions' => [ qw(
|
||||
loadConfigFromDB
|
||||
saveConfigToDB
|
||||
) ]
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
|
@ -67,99 +67,138 @@ use Carp;
|
|||
|
||||
sub loadConfigFromDB
|
||||
{
|
||||
print( "Loading config from DB\n" );
|
||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
||||
|
||||
if ( !$dbh )
|
||||
{
|
||||
print( "Error: unable to load options from database: $DBI::errstr\n" );
|
||||
return( 0 );
|
||||
}
|
||||
my $sql = "select * from Config";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() );
|
||||
my $option_count = 0;
|
||||
while( my $config = $sth->fetchrow_hashref() )
|
||||
{
|
||||
my ( $name, $value ) = ( $config->{Name}, $config->{Value} );
|
||||
#print( "Name = '$name'\n" );
|
||||
my $option = $options_hash{$name};
|
||||
if ( !$option )
|
||||
{
|
||||
warn( "No option '$name' found, removing" );
|
||||
next;
|
||||
}
|
||||
#next if ( $option->{category} eq 'hidden' );
|
||||
if ( defined($value) )
|
||||
{
|
||||
if ( $option->{type} == $types{boolean} )
|
||||
{
|
||||
$option->{value} = $value?"yes":"no";
|
||||
}
|
||||
else
|
||||
{
|
||||
$option->{value} = $value;
|
||||
}
|
||||
}
|
||||
$option_count++;;
|
||||
}
|
||||
$sth->finish();
|
||||
$dbh->disconnect();
|
||||
return( $option_count );
|
||||
print( "Loading config from DB\n" );
|
||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.";host=".$Config{ZM_DB_HOST}
|
||||
,$Config{ZM_DB_USER}
|
||||
,$Config{ZM_DB_PASS}
|
||||
);
|
||||
|
||||
if ( !$dbh )
|
||||
{
|
||||
print( "Error: unable to load options from database: $DBI::errstr\n" );
|
||||
return( 0 );
|
||||
}
|
||||
my $sql = "select * from Config";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or croak( "Can't execute: ".$sth->errstr() );
|
||||
my $option_count = 0;
|
||||
while( my $config = $sth->fetchrow_hashref() )
|
||||
{
|
||||
my ( $name, $value ) = ( $config->{Name}, $config->{Value} );
|
||||
#print( "Name = '$name'\n" );
|
||||
my $option = $options_hash{$name};
|
||||
if ( !$option )
|
||||
{
|
||||
warn( "No option '$name' found, removing" );
|
||||
next;
|
||||
}
|
||||
#next if ( $option->{category} eq 'hidden' );
|
||||
if ( defined($value) )
|
||||
{
|
||||
if ( $option->{type} == $types{boolean} )
|
||||
{
|
||||
$option->{value} = $value?"yes":"no";
|
||||
}
|
||||
else
|
||||
{
|
||||
$option->{value} = $value;
|
||||
}
|
||||
}
|
||||
$option_count++;;
|
||||
}
|
||||
$sth->finish();
|
||||
$dbh->disconnect();
|
||||
return( $option_count );
|
||||
}
|
||||
|
||||
sub saveConfigToDB
|
||||
{
|
||||
print( "Saving config to DB\n" );
|
||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
||||
print( "Saving config to DB\n" );
|
||||
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.";host=".$Config{ZM_DB_HOST}
|
||||
,$Config{ZM_DB_USER}
|
||||
,$Config{ZM_DB_PASS}
|
||||
);
|
||||
|
||||
if ( !$dbh )
|
||||
{
|
||||
print( "Error: unable to save options to database: $DBI::errstr\n" );
|
||||
return( 0 );
|
||||
}
|
||||
if ( !$dbh )
|
||||
{
|
||||
print( "Error: unable to save options to database: $DBI::errstr\n" );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
my $ac = $dbh->{AutoCommit};
|
||||
$dbh->{AutoCommit} = 0;
|
||||
|
||||
$dbh->do('LOCK TABLE Config WRITE') or croak( "Can't lock Config table: " . $dbh->errstr() );
|
||||
$dbh->do('LOCK TABLE Config WRITE')
|
||||
or croak( "Can't lock Config table: " . $dbh->errstr() );
|
||||
|
||||
my $sql = "delete from Config";
|
||||
my $res = $dbh->do( $sql ) or croak( "Can't do '$sql': ".$dbh->errstr() );
|
||||
my $sql = "delete from Config";
|
||||
my $res = $dbh->do( $sql )
|
||||
or croak( "Can't do '$sql': ".$dbh->errstr() );
|
||||
|
||||
$sql = "replace into Config set Id = ?, Name = ?, Value = ?, Type = ?, DefaultValue = ?, Hint = ?, Pattern = ?, Format = ?, Prompt = ?, Help = ?, Category = ?, Readonly = ?, Requires = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
foreach my $option ( @options )
|
||||
{
|
||||
#next if ( $option->{category} eq 'hidden' );
|
||||
#print( $option->{name}."\n" ) if ( !$option->{category} );
|
||||
$option->{db_type} = $option->{type}->{db_type};
|
||||
$option->{db_hint} = $option->{type}->{hint};
|
||||
$option->{db_pattern} = $option->{type}->{pattern};
|
||||
$option->{db_format} = $option->{type}->{format};
|
||||
if ( $option->{db_type} eq "boolean" )
|
||||
{
|
||||
$option->{db_value} = ($option->{value} eq "yes")?"1":"0";
|
||||
}
|
||||
else
|
||||
{
|
||||
$option->{db_value} = $option->{value};
|
||||
}
|
||||
if ( my $requires = $option->{requires} )
|
||||
{
|
||||
$option->{db_requires} = join( ";", map { my $value = $_->{value}; $value = ($value eq "yes")?1:0 if ( $options_hash{$_->{name}}->{db_type} eq "boolean" ); ( "$_->{name}=$value" ) } @$requires );
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
my $res = $sth->execute( $option->{id}, $option->{name}, $option->{db_value}, $option->{db_type}, $option->{default}, $option->{db_hint}, $option->{db_pattern}, $option->{db_format}, $option->{description}, $option->{help}, $option->{category}, $option->{readonly}?1:0, $option->{db_requires} ) or croak( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
$sth->finish();
|
||||
$sql = "replace into Config set Id = ?, Name = ?, Value = ?, Type = ?, DefaultValue = ?, Hint = ?, Pattern = ?, Format = ?, Prompt = ?, Help = ?, Category = ?, Readonly = ?, Requires = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
foreach my $option ( @options )
|
||||
{
|
||||
#next if ( $option->{category} eq 'hidden' );
|
||||
#print( $option->{name}."\n" ) if ( !$option->{category} );
|
||||
$option->{db_type} = $option->{type}->{db_type};
|
||||
$option->{db_hint} = $option->{type}->{hint};
|
||||
$option->{db_pattern} = $option->{type}->{pattern};
|
||||
$option->{db_format} = $option->{type}->{format};
|
||||
if ( $option->{db_type} eq "boolean" )
|
||||
{
|
||||
$option->{db_value} = ($option->{value} eq "yes")
|
||||
? "1"
|
||||
: "0"
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
$option->{db_value} = $option->{value};
|
||||
}
|
||||
if ( my $requires = $option->{requires} )
|
||||
{
|
||||
$option->{db_requires} = join( ";",
|
||||
map {
|
||||
my $value = $_->{value};
|
||||
$value = ($value eq "yes")
|
||||
? 1
|
||||
: 0
|
||||
if ( $options_hash{$_->{name}}->{db_type} eq "boolean" )
|
||||
; ( "$_->{name}=$value" )
|
||||
} @$requires
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
my $res = $sth->execute(
|
||||
$option->{id},
|
||||
$option->{name},
|
||||
$option->{db_value},
|
||||
$option->{db_type},
|
||||
$option->{default},
|
||||
$option->{db_hint},
|
||||
$option->{db_pattern},
|
||||
$option->{db_format},
|
||||
$option->{description},
|
||||
$option->{help},
|
||||
$option->{category},
|
||||
$option->{readonly} ? 1 : 0,
|
||||
$option->{db_requires}
|
||||
) or croak( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
$dbh->do('UNLOCK TABLES');
|
||||
$dbh->{AutoCommit} = $ac;
|
||||
|
||||
$dbh->disconnect();
|
||||
$dbh->disconnect();
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -179,9 +218,15 @@ ZoneMinder::ConfigAdmin - ZoneMinder Configuration Administration module
|
|||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The ZoneMinder:ConfigAdmin module contains the master definition of the ZoneMinder configuration options as well as helper methods. This module is intended for specialist confguration management and would not normally be used by end users.
|
||||
The ZoneMinder:ConfigAdmin module contains the master definition of the
|
||||
ZoneMinder configuration options as well as helper methods. This module is
|
||||
intended for specialist confguration management and would not normally be
|
||||
used by end users.
|
||||
|
||||
The configuration held in this module, which was previously in zmconfig.pl, includes the name, default value, description, help text, type and category for each option, as well as a number of additional fields in a small number of cases.
|
||||
The configuration held in this module, which was previously in zmconfig.pl,
|
||||
includes the name, default value, description, help text, type and category
|
||||
for each option, as well as a number of additional fields in a small number
|
||||
of cases.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
|
@ -189,11 +234,19 @@ The configuration held in this module, which was previously in zmconfig.pl, incl
|
|||
|
||||
=item loadConfigFromDB ();
|
||||
|
||||
Loads existing configuration from the database (if any) and merges it with the definitions held in this module. This results in the merging of any new configuration and the removal of any deprecated configuration while preserving the existing values of every else.
|
||||
Loads existing configuration from the database (if any) and merges it with
|
||||
the definitions held in this module. This results in the merging of any new
|
||||
configuration and the removal of any deprecated configuration while
|
||||
preserving the existing values of every else.
|
||||
|
||||
=item saveConfigToDB ();
|
||||
|
||||
Saves configuration held in memory to the database. The act of loading and saving configuration is a convenient way to ensure that the configuration held in the database corresponds with the most recent definitions and that all components are using the same set of configuration.
|
||||
Saves configuration held in memory to the database. The act of loading and
|
||||
saving configuration is a convenient way to ensure that the configuration
|
||||
held in the database corresponds with the most recent definitions and that
|
||||
all components are using the same set of configuration.
|
||||
|
||||
=back
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the base class definitions for the camera control
|
||||
# This module contains the base class definitions for the camera control
|
||||
# protocol implementations
|
||||
#
|
||||
package ZoneMinder::Control;
|
||||
|
@ -45,17 +45,17 @@ our $AUTOLOAD;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = {};
|
||||
$self->{name} = "PelcoD";
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = {};
|
||||
$self->{name} = "PelcoD";
|
||||
if ( !defined($id) )
|
||||
{
|
||||
Fatal( "No monitor defined when invoking protocol ".$self->{name} );
|
||||
}
|
||||
$self->{id} = $id;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
$self->{id} = $id;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub DESTROY
|
||||
|
@ -64,32 +64,32 @@ sub DESTROY
|
|||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
croak( "Can't access $name member of object of class $class" );
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
croak( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
|
||||
sub getKey()
|
||||
sub getKey
|
||||
{
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
return( $self->{id} );
|
||||
}
|
||||
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
Fatal( "No open method defined for protocol ".$self->{name} );
|
||||
}
|
||||
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
Fatal( "No close method defined for protocol ".$self->{name} );
|
||||
}
|
||||
|
||||
|
@ -145,9 +145,9 @@ sub executeCommand
|
|||
&{$self->{$command}}( $self, $params );
|
||||
}
|
||||
|
||||
sub printMsg()
|
||||
sub printMsg
|
||||
{
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
Fatal( "No printMsg method defined for protocol ".$self->{name} );
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
#
|
||||
# This module contains the implementation of the 3S camera control
|
||||
# protocol
|
||||
#Model: N5071
|
||||
#Hardware Version: 00
|
||||
#Firmware Version: V1.03_STD-1
|
||||
#Firmware Build Time: Jun 19 2012 15:28:17
|
||||
#Model: N5071
|
||||
#Hardware Version: 00
|
||||
#Firmware Version: V1.03_STD-1
|
||||
#Firmware Build Time: Jun 19 2012 15:28:17
|
||||
|
||||
package ZoneMinder::Control::3S;
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ our @ISA = qw(ZoneMinder::Control);
|
|||
# of the position of your mouse on the arrow.
|
||||
# Extremity of arrow equal to fastest speed of movement
|
||||
# Close the base of arrow to lowest speed of movement
|
||||
# for diagonaly you can click before the begining of the arrow for low speed
|
||||
# for diagonaly you can click before the beginning of the arrow for low speed
|
||||
# In round center equal to stop to move and switch of latest OSD
|
||||
# -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted)
|
||||
# -Zoom Tele switch ON InfraRed LED and stay to manual IR MODE
|
||||
|
@ -63,7 +63,7 @@ our @ISA = qw(ZoneMinder::Control);
|
|||
# -8 Preset PTZ are implemented and functionnal
|
||||
# -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section
|
||||
# -This script is compatible with the basic authentification method used by mostly new camera based with hi3510 chipset
|
||||
# -AutoStop function is active and you must set up value (in sec exemple 0.7) under AutoStop section
|
||||
# -AutoStop function is active and you must set up value (in sec example 0.7) under AutoStop section
|
||||
# or you can set up to 0 for disable it (in this case you need to click to the circle center for stop)
|
||||
# -"White In" to control Brightness, "auto" for restore the original value of Brightness
|
||||
# -"White Out" to control Contrast, "man" for restore the original value of Contrast
|
||||
|
@ -129,7 +129,7 @@ sub printMsg
|
|||
}
|
||||
|
||||
sub sendCmd
|
||||
{
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
my $result = undef;
|
||||
|
@ -211,7 +211,7 @@ sub moveConUp
|
|||
if ( $tiltspeed < 10 ) {
|
||||
$tiltspeed = 1;
|
||||
}
|
||||
Debug( "Move Up" );
|
||||
Debug( "Move Up" );
|
||||
if ( $osd eq "on" )
|
||||
{
|
||||
my $cmd = "param.cgi?cmd=setoverlayattr&-region=1&-show=1&-name=Move Up $tiltspeed";
|
||||
|
@ -658,9 +658,9 @@ sub presetGoto
|
|||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
=head1 FI-8608W
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Database - Perl extension for FOSCAM FI-8608W by Christophe_Y2k
|
||||
ZoneMinder::Control::FI-8608W - Perl extension for FOSCAM FI-8608W by Christophe_Y2k
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ our @ISA = qw(ZoneMinder::Control);
|
|||
# of the position of your mouse on the arrow.
|
||||
# Extremity of arrow equal to fastest speed of movement
|
||||
# Close the base of arrow to lowest speed of movement
|
||||
# for diagonaly you can click before the begining of the arrow for low speed
|
||||
# for diagonaly you can click before the beginning of the arrow for low speed
|
||||
# In round center equal to stop to move
|
||||
# -You can clic directly on the image that equal to click on arrow (for the left there is a bug in zoneminder speed is inverted)
|
||||
# -Zoom Tele/Wide with time control to simulate speed because speed value do not work (buggy firmware or not implemented on this cam)
|
||||
|
@ -67,7 +67,7 @@ our @ISA = qw(ZoneMinder::Control);
|
|||
# You Need to configure ZoneMinder PANSPEED & TILTSEPPED & ZOOMSPEED 1 to 63 by 1 step
|
||||
# -This Script use for login "admin" this hardcoded and your password must setup in "Control Device" section
|
||||
# -This script is compatible with the basic authentification method used by mostly new camera
|
||||
# -AutoStop function is active and you must set up value (in sec exemple 0.5) under AutoStop section
|
||||
# -AutoStop function is active and you must set up value (in sec example 0.5) under AutoStop section
|
||||
# or you can set up to 0 for disable it but the camera never stop to move and trust me, she can move all the night...
|
||||
# (you need to click to the center arrow for stop)
|
||||
# -"White In" to control Brightness, "auto" for restore the original value of Brightness
|
||||
|
@ -734,9 +734,9 @@ sub presetGoto
|
|||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
=head1 FI8620
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Database - Perl extension for FOSCAM FI8620
|
||||
ZoneMinder::Control::FI8620 - Perl extension for FOSCAM FI8620
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
|
|
|
@ -43,176 +43,176 @@ use ZoneMinder::Config qw(:all);
|
|||
use Time::HiRes qw( usleep );
|
||||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = ZoneMinder::Control->new( $id );
|
||||
bless( $self, $class );
|
||||
srand( time() );
|
||||
return $self;
|
||||
{
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
my $self = ZoneMinder::Control->new( $id );
|
||||
bless( $self, $class );
|
||||
srand( time() );
|
||||
return $self;
|
||||
}
|
||||
|
||||
our $AUTOLOAD;
|
||||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
Fatal( "Can't access $name member of object of class $class" );
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
Fatal( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
|
||||
$self->loadMonitor();
|
||||
$self->loadMonitor();
|
||||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION );
|
||||
|
||||
$self->{state} = 'open';
|
||||
$self->{state} = 'open';
|
||||
}
|
||||
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
}
|
||||
|
||||
sub printMsg
|
||||
{
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
}
|
||||
|
||||
sub sendCmd
|
||||
{
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
my $result = undef;
|
||||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
my $result = undef;
|
||||
|
||||
my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice};
|
||||
my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice};
|
||||
|
||||
if ( !defined $password ) {
|
||||
# If value of "Control device" does not consist of two parts, then only password is given and we fallback to default user:
|
||||
$password = $user;
|
||||
$user = 'admin';
|
||||
}
|
||||
if ( !defined $password ) {
|
||||
# If value of "Control device" does not consist of two parts, then only password is given and we fallback to default user:
|
||||
$password = $user;
|
||||
$user = 'admin';
|
||||
}
|
||||
|
||||
$cmd .= "user=$user&pwd=$password";
|
||||
$cmd .= "user=$user&pwd=$password";
|
||||
|
||||
printMsg( $cmd, "Tx" );
|
||||
printMsg( $cmd, "Tx" );
|
||||
|
||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
|
||||
my $res = $self->{ua}->request($req);
|
||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
|
||||
my $res = $self->{ua}->request($req);
|
||||
|
||||
if ( $res->is_success )
|
||||
{
|
||||
$result = !undef;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Error check failed: '".$res->status_line()."' for URL ".$req->uri() );
|
||||
}
|
||||
if ( $res->is_success )
|
||||
{
|
||||
$result = !undef;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Error check failed: '".$res->status_line()."' for URL ".$req->uri() );
|
||||
}
|
||||
|
||||
return( $result );
|
||||
return( $result );
|
||||
}
|
||||
|
||||
sub reset
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Camera Reset" );
|
||||
$self->sendCmd( 'reboot.cgi?' );
|
||||
my $self = shift;
|
||||
Debug( "Camera Reset" );
|
||||
$self->sendCmd( 'reboot.cgi?' );
|
||||
}
|
||||
|
||||
#Up Arrow
|
||||
sub moveConUp
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Up" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=0&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Up" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=0&' );
|
||||
}
|
||||
|
||||
#Down Arrow
|
||||
sub moveConDown
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Down" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=2&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Down" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=2&' );
|
||||
}
|
||||
|
||||
#Left Arrow
|
||||
sub moveConLeft
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Left" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=6&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Left" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=6&' );
|
||||
}
|
||||
|
||||
#Right Arrow
|
||||
sub moveConRight
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Right" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=4&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Right" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=4&' );
|
||||
}
|
||||
|
||||
#Diagonally Up Right Arrow
|
||||
sub moveConUpRight
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Up Right" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=90&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Up Right" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=90&' );
|
||||
}
|
||||
|
||||
#Diagonally Down Right Arrow
|
||||
sub moveConDownRight
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Down Right" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=92&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Down Right" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=92&' );
|
||||
}
|
||||
|
||||
#Diagonally Up Left Arrow
|
||||
sub moveConUpLeft
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Up Left" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=91&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Up Left" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=91&' );
|
||||
}
|
||||
|
||||
#Diagonally Down Left Arrow
|
||||
sub moveConDownLeft
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Down Left" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=93&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Diagonally Down Left" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=93&' );
|
||||
}
|
||||
|
||||
#Stop
|
||||
sub moveStop
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Move Stop" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=1&' );
|
||||
my $self = shift;
|
||||
Debug( "Move Stop" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=1&' );
|
||||
}
|
||||
|
||||
#Move Camera to Home Position
|
||||
sub presetHome
|
||||
{
|
||||
my $self = shift;
|
||||
Debug( "Home Preset" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=25&' );
|
||||
my $self = shift;
|
||||
Debug( "Home Preset" );
|
||||
$self->sendCmd( 'decoder_control.cgi?command=25&' );
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -220,12 +220,17 @@ sub presetHome
|
|||
__END__
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Control::FI8908W - Foscam FI8908W camera control
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains the implementation of the Foscam FI8908W / FI8918W IP camera control
|
||||
protocol.
|
||||
This module contains the implementation of the Foscam FI8908W / FI8918W IP
|
||||
camera control protocol.
|
||||
|
||||
The module uses "Control Device" value to retrieve user and password. User
|
||||
and password should be separated by colon, e.g. user:password. If colon is
|
||||
not provided, then "admin" is used as a fallback value for the user.
|
||||
|
||||
The module uses "Control Device" value to retrieve user and password. User and password should
|
||||
be separated by colon, e.g. user:password. If colon is not provided, then "admin" is used
|
||||
as a fallback value for the user.
|
||||
=cut
|
||||
|
|
|
@ -102,7 +102,6 @@ sub close
|
|||
|
||||
sub printMsg
|
||||
{
|
||||
my $self = shift;
|
||||
my $msg = shift;
|
||||
my $msg_len = length($msg);
|
||||
Debug( $msg."[".$msg_len."]" );
|
||||
|
@ -113,9 +112,28 @@ sub sendCmd
|
|||
my $self = shift;
|
||||
my $cmd = shift;
|
||||
my $result = undef;
|
||||
|
||||
my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice};
|
||||
if ( ! $password ) {
|
||||
$password = $user;
|
||||
$user = 'admin';
|
||||
}
|
||||
$user = 'admin' if ! $user;
|
||||
$password = 'pwd' if ! $password;
|
||||
|
||||
$cmd .= "&usr=$user&pwd=$password";
|
||||
|
||||
printMsg( $cmd, "Tx" );
|
||||
my $temps = time();
|
||||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/cgi-bin/CGIProxy.fcgi?usr%3Dadmin%26pwd%3D".$self->{Monitor}->{ControlDevice}."%26cmd%3D".$cmd."%26".$temps );
|
||||
my $url;
|
||||
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
||||
$url = $self->{Monitor}->{ControlAddress};
|
||||
} else {
|
||||
$url = "http://".$self->{Monitor}->{ControlAddress};
|
||||
}
|
||||
$url .= "/cgi-bin/CGIProxy.fcgi?cmd=$cmd%26".time;
|
||||
printMsg( $url, "Tx" );
|
||||
|
||||
my $req = HTTP::Request->new( GET=>$url );
|
||||
my $res = $self->{ua}->request($req);
|
||||
if ( $res->is_success )
|
||||
{
|
||||
|
@ -134,7 +152,7 @@ sub reset
|
|||
# Setup OSD
|
||||
my $cmd = "setOSDSetting%26isEnableTimeStamp%3D0%26isEnableDevName%3D1%26dispPos%3D0%26isEnabledOSDMask%3D0";
|
||||
$self->sendCmd( $cmd );
|
||||
# Setup For Stream=0 Resolution=720p Bandwith=4M FPS=30 KeyFrameInterval/GOP=100 VBR=ON
|
||||
# Setup For Stream=0 Resolution=720p Bandwidth=4M FPS=30 KeyFrameInterval/GOP=100 VBR=ON
|
||||
$cmd = "setVideoStreamParam%26streamType%3D0%26resolution%3D0%26bitRate%3D4194304%26frameRate%3D30%26GOP%3D100%26isVBR%3D1";
|
||||
$self->sendCmd( $cmd );
|
||||
# Setup For Infrared AUTO
|
||||
|
@ -696,9 +714,9 @@ sub presetGoto
|
|||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
=head1 FI9821W
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Database - Perl extension for FOSCAM FI9821W
|
||||
ZoneMinder::Control::FI9821W - Perl extension for FOSCAM FI9821W
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
|
|
|
@ -107,14 +107,18 @@ sub sendCmd {
|
|||
printMsg( $cmd, "Tx" );
|
||||
#print( "http://$address/$cmd\n" );
|
||||
#my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
|
||||
|
||||
my $url;
|
||||
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
||||
$url = $self->{Monitor}->{ControlAddress}.'/cgi-bin/setGPIO.cgi?preventCache='.time;
|
||||
} else {
|
||||
$url = 'http://'.$self->{Monitor}->{ControlAddress}.'/cgi-bin/setGPIO.cgi?preventCache='.time;
|
||||
} # en dif
|
||||
Error("Url: $url $cmd");
|
||||
|
||||
my $url;
|
||||
if ( $self->{Monitor}->{ControlAddress} =~ /^http/ ) {
|
||||
$url = $self->{Monitor}->{ControlAddress}
|
||||
.'/cgi-bin/setGPIO.cgi?preventCache='.time
|
||||
;
|
||||
} else {
|
||||
$url = 'http://'.$self->{Monitor}->{ControlAddress}
|
||||
.'/cgi-bin/setGPIO.cgi?preventCache='.time
|
||||
;
|
||||
} # en dif
|
||||
Error("Url: $url $cmd");
|
||||
my $uri = URI::Encode->new( { encode_reserved => 0 } );
|
||||
my $encoded = $uri->encode( $cmd );
|
||||
my $res = $self->{ua}->post( $url, Content=>"data=$encoded" );
|
||||
|
@ -203,7 +207,11 @@ sub moveMap
|
|||
my $xcoord = $self->getParam( $params, 'xcoord' );
|
||||
my $ycoord = $self->getParam( $params, 'ycoord' );
|
||||
Debug( "Move Map to $xcoord,$ycoord" );
|
||||
my $cmd = "/axis-cgi/com/ptz.cgi?center=$xcoord,$ycoord&imagewidth=".$self->{Monitor}->{Width}."&imageheight=".$self->{Monitor}->{Height};
|
||||
my $cmd = "/axis-cgi/com/ptz.cgi?center=$xcoord,$ycoord&imagewidth="
|
||||
.$self->{Monitor}->{Width}
|
||||
."&imageheight="
|
||||
.$self->{Monitor}->{Height}
|
||||
;
|
||||
$self->sendCmd( $cmd );
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
# This module contains the implementation of the Pelco-P camera control
|
||||
# protocol
|
||||
#
|
||||
package ZoneMinder::Control::PelcoD;
|
||||
package ZoneMinder::Control::PelcoP;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
|
|
|
@ -60,16 +60,16 @@ our @ISA = qw(ZoneMinder::Control);
|
|||
|
||||
#
|
||||
# ******** YOU MUST CHANGE THE FOLLOWING LINES TO MATCH YOUR CAMERA! **********
|
||||
#
|
||||
#
|
||||
# I assume that "TV-IP672WI" would work for the TV-IP672WI, but can't test since I don't own one.
|
||||
#
|
||||
#
|
||||
# TV-IP672PI works for the PI version, of course.
|
||||
#
|
||||
# Finally, the username is the username you'd like to authenticate as.
|
||||
#
|
||||
our $REALM = 'TV-IP862IC';
|
||||
our $USERNAME = 'admin';
|
||||
our $PASSWORD = '';
|
||||
our $PASSWORD = '';
|
||||
our $ADDRESS = '';
|
||||
|
||||
# ==========================================================================
|
||||
|
@ -111,26 +111,32 @@ sub open
|
|||
my $self = shift;
|
||||
$self->loadMonitor();
|
||||
|
||||
my ( $protocol, $username, $password, $address ) = $self->{Monitor}->{ControlAddress} =~ /^(https?:\/\/)?([^:]+):([^\/@]+)@(.*)$/;
|
||||
if ( $username ) {
|
||||
$USERNAME = $username;
|
||||
$PASSWORD = $password;
|
||||
$ADDRESS = $address;
|
||||
} else {
|
||||
Error( "Failed to parse auth from address");
|
||||
$ADDRESS = $self->{Monitor}->{ControlAddress};
|
||||
}
|
||||
if ( ! $ADDRESS =~ /:/ ) {
|
||||
Error( "You generally need to also specify the port. I will append :80" );
|
||||
$ADDRESS .= ':80';
|
||||
}
|
||||
my ( $protocol, $username, $password, $address )
|
||||
= $self->{Monitor}->{ControlAddress} =~ /^(https?:\/\/)?([^:]+):([^\/@]+)@(.*)$/;
|
||||
if ( $username ) {
|
||||
$USERNAME = $username;
|
||||
$PASSWORD = $password;
|
||||
$ADDRESS = $address;
|
||||
} else {
|
||||
Error( "Failed to parse auth from address");
|
||||
$ADDRESS = $self->{Monitor}->{ControlAddress};
|
||||
}
|
||||
if ( ! $ADDRESS =~ /:/ ) {
|
||||
Error( "You generally need to also specify the port. I will append :80" );
|
||||
$ADDRESS .= ':80';
|
||||
}
|
||||
|
||||
use LWP::UserAgent;
|
||||
$self->{ua} = LWP::UserAgent->new;
|
||||
$self->{ua}->agent( "ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION );
|
||||
$self->{state} = 'open';
|
||||
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
|
||||
Debug ( "sendCmd credentials control address:'".$ADDRESS."' realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'");
|
||||
# credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string)
|
||||
Debug ( "sendCmd credentials control address:'".$ADDRESS
|
||||
."' realm:'" . $REALM
|
||||
. "' username:'" . $USERNAME
|
||||
. "' password:'".$PASSWORD
|
||||
."'"
|
||||
);
|
||||
$self->{ua}->credentials($ADDRESS,$REALM,$USERNAME,$PASSWORD);
|
||||
}
|
||||
|
||||
|
@ -159,29 +165,29 @@ sub sendCmd
|
|||
|
||||
my $result = undef;
|
||||
|
||||
my $url = "http://".$ADDRESS."/cgi/ptdc.cgi?command=".$cmd;
|
||||
my $url = "http://".$ADDRESS."/cgi/ptdc.cgi?command=".$cmd;
|
||||
my $req = HTTP::Request->new( GET=>$url );
|
||||
|
||||
Debug ("sendCmd command: " . $url );
|
||||
|
||||
|
||||
my $res = $self->{ua}->request($req);
|
||||
|
||||
if ( $res->is_success ) {
|
||||
$result = !undef;
|
||||
} else {
|
||||
if ( $res->status_line() eq '401 Unauthorized' ) {
|
||||
Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||
Error("Content was " . $res->content() );
|
||||
my $res = $self->{ua}->request($req);
|
||||
if ( $res->is_success ) {
|
||||
$result = !undef;
|
||||
} else {
|
||||
Error("Content was " . $res->content() );
|
||||
}
|
||||
}
|
||||
if ( ! $result ) {
|
||||
Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
|
||||
}
|
||||
if ( $res->status_line() eq '401 Unauthorized' ) {
|
||||
Error( "Error check failed, trying again: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||
Error("Content was " . $res->content() );
|
||||
my $res = $self->{ua}->request($req);
|
||||
if ( $res->is_success ) {
|
||||
$result = !undef;
|
||||
} else {
|
||||
Error("Content was " . $res->content() );
|
||||
}
|
||||
}
|
||||
if ( ! $result ) {
|
||||
Error( "Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
|
||||
}
|
||||
}
|
||||
|
||||
return( $result );
|
||||
|
@ -203,10 +209,10 @@ sub sendCmdPost
|
|||
my $result = undef;
|
||||
|
||||
if ($url eq undef)
|
||||
{
|
||||
Error ("url passed to sendCmdPost is undefined.");
|
||||
return(-1);
|
||||
}
|
||||
{
|
||||
Error ("url passed to sendCmdPost is undefined.");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
Debug ("sendCmdPost url: " . $url . " cmd: " . $cmd);
|
||||
|
||||
|
@ -215,7 +221,7 @@ sub sendCmdPost
|
|||
$req->content($cmd);
|
||||
|
||||
Debug ( "sendCmdPost credentials control address:'".$ADDRESS."' realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'");
|
||||
|
||||
|
||||
my $res = $self->{ua}->request($req);
|
||||
|
||||
if ( $res->is_success )
|
||||
|
@ -225,11 +231,11 @@ sub sendCmdPost
|
|||
else
|
||||
{
|
||||
Error( "sendCmdPost Error check failed: '".$res->status_line()."' cmd:'".$cmd."'" );
|
||||
if ( $res->status_line() eq '401 Unauthorized' ) {
|
||||
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||
} else {
|
||||
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||
} # endif
|
||||
if ( $res->status_line() eq '401 Unauthorized' ) {
|
||||
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||
} else {
|
||||
Error( "sendCmdPost Error check failed: USERNAME: $USERNAME realm: $REALM password: " . $PASSWORD );
|
||||
} # endif
|
||||
}
|
||||
|
||||
return( $result );
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
# Rename to Wanscam
|
||||
# Pan Left/Right switched
|
||||
# IR On/Off switched
|
||||
# Brightness Increase/Decrease in 16 steps
|
||||
#
|
||||
# Brightness Increase/Decrease in 16 steps
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
|
|
@ -126,32 +126,32 @@ sub sendCmd
|
|||
sub Up
|
||||
{
|
||||
my $self = shift;
|
||||
$self->moveConUp();
|
||||
$self->moveConUp();
|
||||
}
|
||||
|
||||
sub Down
|
||||
{
|
||||
my $self = shift;
|
||||
$self->moveConDown();
|
||||
$self->moveConDown();
|
||||
}
|
||||
|
||||
sub Left
|
||||
{
|
||||
my $self = shift;
|
||||
$self->moveConLeft();
|
||||
$self->moveConLeft();
|
||||
}
|
||||
|
||||
sub Right
|
||||
{
|
||||
my $self = shift;
|
||||
$self->moveConRight();
|
||||
$self->moveConRight();
|
||||
}
|
||||
|
||||
|
||||
sub reset
|
||||
{
|
||||
my $self = shift;
|
||||
$self->cameraReset();
|
||||
$self->cameraReset();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ our %CamParams = ();
|
|||
# ==========================================================================
|
||||
#
|
||||
# ONVIF Control Protocol
|
||||
#
|
||||
#
|
||||
# On ControlAddress use the format :
|
||||
# USERNAME:PASSWORD@ADDRESS:PORT
|
||||
# eg : admin:@10.1.2.1:80
|
||||
|
@ -50,7 +50,7 @@ use ZoneMinder::Config qw(:all);
|
|||
use Time::HiRes qw( usleep );
|
||||
|
||||
sub new
|
||||
{
|
||||
{
|
||||
|
||||
my $class = shift;
|
||||
my $id = shift;
|
||||
|
@ -90,7 +90,7 @@ sub open
|
|||
}
|
||||
|
||||
sub close
|
||||
{
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{state} = 'closed';
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ sub getCamParams
|
|||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/get_camera_params.cgi" );
|
||||
my $res = $self->{ua}->request($req);
|
||||
|
||||
if ( $res->is_success )
|
||||
if ( $res->is_success )
|
||||
{
|
||||
# Parse results setting values in %FCParams
|
||||
my $content = $res->decoded_content;
|
||||
|
@ -141,7 +141,7 @@ sub getCamParams
|
|||
while ($content =~ s/var\s+([^=]+)=([^;]+);//ms) {
|
||||
$CamParams{$1} = $2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Error check failed:'".$res->status_line()."'" );
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Database;
|
||||
|
@ -37,17 +37,17 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
|||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
zmDbConnect
|
||||
zmDbDisconnect
|
||||
zmDbGetMonitors
|
||||
zmDbGetMonitor
|
||||
zmDbGetMonitorAndControl
|
||||
) ]
|
||||
zmDbConnect
|
||||
zmDbDisconnect
|
||||
zmDbGetMonitors
|
||||
zmDbGetMonitor
|
||||
zmDbGetMonitorAndControl
|
||||
) ]
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
|
@ -70,37 +70,46 @@ use Carp;
|
|||
|
||||
our $dbh = undef;
|
||||
|
||||
sub zmDbConnect( ;$ )
|
||||
sub zmDbConnect
|
||||
{
|
||||
my $force = shift;
|
||||
if ( $force )
|
||||
{
|
||||
zmDbDisconnect();
|
||||
}
|
||||
if ( !defined( $dbh ) )
|
||||
{
|
||||
my $force = shift;
|
||||
if ( $force )
|
||||
{
|
||||
zmDbDisconnect();
|
||||
}
|
||||
if ( !defined( $dbh ) )
|
||||
{
|
||||
my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
||||
|
||||
if ( defined($port) )
|
||||
{
|
||||
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$host.";port=".$port, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
||||
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.";host=".$host
|
||||
.";port=".$port
|
||||
, $Config{ZM_DB_USER}
|
||||
, $Config{ZM_DB_PASS}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
||||
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.";host=".$Config{ZM_DB_HOST}
|
||||
, $Config{ZM_DB_USER}
|
||||
, $Config{ZM_DB_PASS}
|
||||
);
|
||||
}
|
||||
$dbh->trace( 0 );
|
||||
}
|
||||
return( $dbh );
|
||||
}
|
||||
return( $dbh );
|
||||
}
|
||||
|
||||
sub zmDbDisconnect()
|
||||
sub zmDbDisconnect
|
||||
{
|
||||
if ( defined( $dbh ) )
|
||||
{
|
||||
$dbh->disconnect();
|
||||
$dbh = undef;
|
||||
}
|
||||
if ( defined( $dbh ) )
|
||||
{
|
||||
$dbh->disconnect();
|
||||
$dbh = undef;
|
||||
}
|
||||
}
|
||||
|
||||
use constant DB_MON_ALL => 0; # All monitors
|
||||
|
@ -110,78 +119,88 @@ use constant DB_MON_MOTION => 3; # All monitors that are doing motion detection
|
|||
use constant DB_MON_RECORD => 4; # All monitors that are doing unconditional recording
|
||||
use constant DB_MON_PASSIVE => 5; # All monitors that are in nodect state
|
||||
|
||||
sub zmDbGetMonitors( ;$ )
|
||||
sub zmDbGetMonitors
|
||||
{
|
||||
zmDbConnect();
|
||||
zmDbConnect();
|
||||
|
||||
my $function = shift || DB_MON_ALL;
|
||||
my $sql = "select * from Monitors";
|
||||
my $function = shift || DB_MON_ALL;
|
||||
my $sql = "select * from Monitors";
|
||||
|
||||
if ( $function )
|
||||
{
|
||||
if ( $function == DB_MON_CAPT )
|
||||
{
|
||||
$sql .= " where Function >= 'Monitor'";
|
||||
}
|
||||
elsif ( $function == DB_MON_ACTIVE )
|
||||
{
|
||||
$sql .= " where Function > 'Monitor'";
|
||||
}
|
||||
elsif ( $function == DB_MON_MOTION )
|
||||
{
|
||||
$sql .= " where Function = 'Modect' or Function = 'Mocord'";
|
||||
}
|
||||
elsif ( $function == DB_MON_RECORD )
|
||||
{
|
||||
$sql .= " where Function = 'Record' or Function = 'Mocord'";
|
||||
}
|
||||
elsif ( $function == DB_MON_PASSIVE )
|
||||
{
|
||||
$sql .= " where Function = 'Nodect'";
|
||||
}
|
||||
}
|
||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or croak( "Can't execute '$sql': ".$sth->errstr() );
|
||||
if ( $function )
|
||||
{
|
||||
if ( $function == DB_MON_CAPT )
|
||||
{
|
||||
$sql .= " where Function >= 'Monitor'";
|
||||
}
|
||||
elsif ( $function == DB_MON_ACTIVE )
|
||||
{
|
||||
$sql .= " where Function > 'Monitor'";
|
||||
}
|
||||
elsif ( $function == DB_MON_MOTION )
|
||||
{
|
||||
$sql .= " where Function = 'Modect' or Function = 'Mocord'";
|
||||
}
|
||||
elsif ( $function == DB_MON_RECORD )
|
||||
{
|
||||
$sql .= " where Function = 'Record' or Function = 'Mocord'";
|
||||
}
|
||||
elsif ( $function == DB_MON_PASSIVE )
|
||||
{
|
||||
$sql .= " where Function = 'Nodect'";
|
||||
}
|
||||
}
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or croak( "Can't execute '$sql': ".$sth->errstr() );
|
||||
|
||||
my @monitors;
|
||||
my @monitors;
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
push( @monitors, $monitor );
|
||||
}
|
||||
$sth->finish();
|
||||
return( \@monitors );
|
||||
push( @monitors, $monitor );
|
||||
}
|
||||
$sth->finish();
|
||||
return( \@monitors );
|
||||
}
|
||||
|
||||
sub zmDbGetMonitor( $ )
|
||||
sub zmDbGetMonitor
|
||||
{
|
||||
zmDbConnect();
|
||||
zmDbConnect();
|
||||
|
||||
my $id = shift;
|
||||
my $id = shift;
|
||||
|
||||
return( undef ) if ( !defined($id) );
|
||||
return( undef ) if ( !defined($id) );
|
||||
|
||||
my $sql = "select * from Monitors where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $id ) or croak( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sql = "select * from Monitors where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or croak( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $id )
|
||||
or croak( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $monitor = $sth->fetchrow_hashref();
|
||||
|
||||
return( $monitor );
|
||||
return( $monitor );
|
||||
}
|
||||
|
||||
sub zmDbGetMonitorAndControl( $ )
|
||||
sub zmDbGetMonitorAndControl
|
||||
{
|
||||
zmDbConnect();
|
||||
zmDbConnect();
|
||||
|
||||
my $id = shift;
|
||||
my $id = shift;
|
||||
|
||||
return( undef ) if ( !defined($id) );
|
||||
return( undef ) if ( !defined($id) );
|
||||
|
||||
my $sql = "select C.*,M.*,C.Protocol from Monitors as M inner join Controls as C on (M.ControlId = C.Id) where M.Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $id ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sql = "SELECT C.*,M.*,C.Protocol
|
||||
FROM Monitors as M
|
||||
INNER JOIN Controls as C on (M.ControlId = C.Id)
|
||||
WHERE M.Id = ?"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $id )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $monitor = $sth->fetchrow_hashref();
|
||||
|
||||
return( $monitor );
|
||||
return( $monitor );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::General;
|
||||
|
@ -76,7 +76,7 @@ use ZoneMinder::Database qw(:all);
|
|||
use POSIX;
|
||||
|
||||
# For running general shell commands
|
||||
sub executeShellCommand( $ )
|
||||
sub executeShellCommand
|
||||
{
|
||||
my $command = shift;
|
||||
my $output = qx( $command );
|
||||
|
@ -90,7 +90,7 @@ sub executeShellCommand( $ )
|
|||
return( $status );
|
||||
}
|
||||
|
||||
sub getCmdFormat()
|
||||
sub getCmdFormat
|
||||
{
|
||||
Debug( "Testing valid shell syntax\n" );
|
||||
|
||||
|
@ -162,7 +162,7 @@ our $testedShellSyntax = 0;
|
|||
our ( $cmdPrefix, $cmdSuffix );
|
||||
|
||||
# For running ZM daemons etc
|
||||
sub runCommand( $ )
|
||||
sub runCommand
|
||||
{
|
||||
if ( !$testedShellSyntax )
|
||||
{
|
||||
|
@ -196,30 +196,45 @@ sub runCommand( $ )
|
|||
return( $output );
|
||||
}
|
||||
|
||||
sub getEventPath( $ )
|
||||
sub getEventPath
|
||||
{
|
||||
my $event = shift;
|
||||
|
||||
my $event_path = "";
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
||||
{
|
||||
$event_path = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.strftime( "%y/%m/%d/%H/%M/%S", localtime($event->{Time}) );
|
||||
$event_path = $Config{ZM_DIR_EVENTS}
|
||||
.'/'.$event->{MonitorId}
|
||||
.'/'.strftime( "%y/%m/%d/%H/%M/%S",
|
||||
localtime($event->{Time})
|
||||
)
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
$event_path = $Config{ZM_DIR_EVENTS}.'/'.$event->{MonitorId}.'/'.$event->{Id};
|
||||
$event_path = $Config{ZM_DIR_EVENTS}
|
||||
.'/'.$event->{MonitorId}
|
||||
.'/'.$event->{Id}
|
||||
;
|
||||
}
|
||||
|
||||
if ( index($Config{ZM_DIR_EVENTS},'/') != 0 ){
|
||||
$event_path = $Config{ZM_PATH_WEB}
|
||||
.'/'.$event_path
|
||||
;
|
||||
}
|
||||
$event_path = $Config{ZM_PATH_WEB}.'/'.$event_path if ( index($Config{ZM_DIR_EVENTS},'/') != 0 );
|
||||
return( $event_path );
|
||||
}
|
||||
|
||||
sub createEventPath( $ )
|
||||
sub createEventPath
|
||||
{
|
||||
#
|
||||
# WARNING assumes running from events directory
|
||||
#
|
||||
my $event = shift;
|
||||
my $eventRootPath = ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
||||
my $eventRootPath = ($Config{ZM_DIR_EVENTS}=~m|/|)
|
||||
? $Config{ZM_DIR_EVENTS}
|
||||
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
||||
my $eventPath = $eventRootPath.'/'.$event->{MonitorId};
|
||||
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
||||
|
@ -242,7 +257,8 @@ sub createEventPath( $ )
|
|||
|
||||
# Create event id symlink
|
||||
my $idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} );
|
||||
symlink( $timePath, $idFile ) or Fatal( "Can't symlink $idFile -> $eventPath: $!" );
|
||||
symlink( $timePath, $idFile )
|
||||
or Fatal( "Can't symlink $idFile -> $eventPath: $!" );
|
||||
|
||||
makePath( $timePath, $eventPath );
|
||||
$eventPath .= '/'.$timePath;
|
||||
|
@ -250,8 +266,9 @@ sub createEventPath( $ )
|
|||
|
||||
# Create empty id tag file
|
||||
$idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} );
|
||||
open( ID_FP, ">$idFile" ) or Fatal( "Can't open $idFile: $!" );
|
||||
close( ID_FP );
|
||||
open( my $ID_FP, ">", $idFile )
|
||||
or Fatal( "Can't open $idFile: $!" );
|
||||
close( $ID_FP );
|
||||
setFileOwner( $idFile );
|
||||
}
|
||||
else
|
||||
|
@ -260,8 +277,9 @@ sub createEventPath( $ )
|
|||
$eventPath .= '/'.$event->{Id};
|
||||
|
||||
my $idFile = sprintf( "%s/.%d", $eventPath, $event->{Id} );
|
||||
open( ID_FP, ">$idFile" ) or Fatal( "Can't open $idFile: $!" );
|
||||
close( ID_FP );
|
||||
open( my $ID_FP, ">", $idFile )
|
||||
or Fatal( "Can't open $idFile: $!" );
|
||||
close( $ID_FP );
|
||||
setFileOwner( $idFile );
|
||||
}
|
||||
return( $eventPath );
|
||||
|
@ -272,15 +290,20 @@ use Data::Dumper;
|
|||
our $_setFileOwner = undef;
|
||||
our ( $_ownerUid, $_ownerGid );
|
||||
|
||||
sub _checkProcessOwner()
|
||||
sub _checkProcessOwner
|
||||
{
|
||||
if ( !defined($_setFileOwner) )
|
||||
{
|
||||
my ( $processOwner ) = getpwuid( $> );
|
||||
if ( $processOwner ne $Config{ZM_WEB_USER} )
|
||||
{
|
||||
# Not running as web user, so should be root in whch case chown the temporary directory
|
||||
( my $ownerName, my $ownerPass, $_ownerUid, $_ownerGid ) = getpwnam( $Config{ZM_WEB_USER} ) or Fatal( "Can't get user details for web user '".$Config{ZM_WEB_USER}."': $!" );
|
||||
# Not running as web user, so should be root in which case chown
|
||||
# the temporary directory
|
||||
( my $ownerName, my $ownerPass, $_ownerUid, $_ownerGid )
|
||||
= getpwnam( $Config{ZM_WEB_USER} )
|
||||
or Fatal( "Can't get user details for web user '"
|
||||
.$Config{ZM_WEB_USER}."': $!"
|
||||
);
|
||||
$_setFileOwner = 1;
|
||||
}
|
||||
else
|
||||
|
@ -291,19 +314,22 @@ sub _checkProcessOwner()
|
|||
return( $_setFileOwner );
|
||||
}
|
||||
|
||||
sub setFileOwner( $ )
|
||||
sub setFileOwner
|
||||
{
|
||||
my $file = shift;
|
||||
|
||||
if ( _checkProcessOwner() )
|
||||
{
|
||||
chown( $_ownerUid, $_ownerGid, $file ) or Fatal( "Can't change ownership of file '$file' to '".$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" );
|
||||
chown( $_ownerUid, $_ownerGid, $file )
|
||||
or Fatal( "Can't change ownership of file '$file' to '"
|
||||
.$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
our $_hasImageInfo = undef;
|
||||
|
||||
sub _checkForImageInfo()
|
||||
sub _checkForImageInfo
|
||||
{
|
||||
if ( !defined($_hasImageInfo) )
|
||||
{
|
||||
|
@ -317,7 +343,7 @@ sub _checkForImageInfo()
|
|||
return( $_hasImageInfo );
|
||||
}
|
||||
|
||||
sub createEvent( $;$ )
|
||||
sub createEvent
|
||||
{
|
||||
my $event = shift;
|
||||
|
||||
|
@ -335,9 +361,14 @@ sub createEvent( $;$ )
|
|||
elsif ( $event->{MonitorId} )
|
||||
{
|
||||
my $sql = "select * from Monitors where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{MonitorId} ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
$event->{monitor} = $sth->fetchrow_hashref() or Fatal( "Unable to create event, can't load monitor with id '".$event->{MonitorId}."'" );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{MonitorId} )
|
||||
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
$event->{monitor} = $sth->fetchrow_hashref()
|
||||
or Fatal( "Unable to create event, can't load monitor with id '"
|
||||
.$event->{MonitorId}."'"
|
||||
);
|
||||
$sth->finish();
|
||||
}
|
||||
else
|
||||
|
@ -358,7 +389,9 @@ sub createEvent( $;$ )
|
|||
my $imageInfo = Image::Info::image_info( $frame->{imagePath} );
|
||||
if ( $imageInfo->{error} )
|
||||
{
|
||||
Error( "Unable to extract image info from '".$frame->{imagePath}."': ".$imageInfo->{error} );
|
||||
Error( "Unable to extract image info from '"
|
||||
.$frame->{imagePath}."': ".$imageInfo->{error}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -394,18 +427,25 @@ sub createEvent( $;$ )
|
|||
push( @values, $event->{$field} );
|
||||
}
|
||||
|
||||
my $sql = "insert into Events (".join(',',@fields).") values (".join(',',@formats).")";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
my $sql = "INSERT INTO Events (".join(',',@fields)
|
||||
.") VALUES (".join(',',@formats).")"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( @values )
|
||||
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
$event->{Id} = $dbh->{mysql_insertid};
|
||||
Info( "Created event ".$event->{Id} );
|
||||
|
||||
if ( $event->{EndTime} )
|
||||
{
|
||||
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} if ( $event->{Name} eq 'New Event' );
|
||||
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id}
|
||||
if ( $event->{Name} eq 'New Event' );
|
||||
my $sql = "update Events set Name = ? where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Name}, $event->{Id} ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Name}, $event->{Id} )
|
||||
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
}
|
||||
|
||||
my $eventPath = createEventPath( $event );
|
||||
|
@ -428,26 +468,46 @@ sub createEvent( $;$ )
|
|||
push( @values, $frame->{$field} );
|
||||
}
|
||||
|
||||
my $sql = "insert into Frames (".join(',',@fields).") values (".join(',',@formats).")";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
my $sql = "insert into Frames (".join(',',@fields)
|
||||
.") values (".join(',',@formats).")"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( @values )
|
||||
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
#$frame->{FrameId} = $dbh->{mysql_insertid};
|
||||
if ( $frame->{imagePath} )
|
||||
{
|
||||
$frame->{capturePath} = sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", $eventPath, $frame->{FrameId} );
|
||||
rename( $frame->{imagePath}, $frame->{capturePath} ) or Fatal( "Can't copy ".$frame->{imagePath}." to ".$frame->{capturePath}.": $!" );
|
||||
$frame->{capturePath} = sprintf(
|
||||
"%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||
."d-capture.jpg"
|
||||
, $eventPath
|
||||
, $frame->{FrameId}
|
||||
);
|
||||
rename( $frame->{imagePath}, $frame->{capturePath} )
|
||||
or Fatal( "Can't copy ".$frame->{imagePath}
|
||||
." to ".$frame->{capturePath}.": $!"
|
||||
);
|
||||
setFileOwner( $frame->{capturePath} );
|
||||
if ( 0 && $Config{ZM_CREATE_ANALYSIS_IMAGES} )
|
||||
{
|
||||
$frame->{analysePath} = sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-analyse.jpg", $eventPath, $frame->{FrameId} );
|
||||
link( $frame->{capturePath}, $frame->{analysePath} ) or Fatal( "Can't link ".$frame->{capturePath}." to ".$frame->{analysePath}.": $!" );
|
||||
$frame->{analysePath} = sprintf(
|
||||
"%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||
."d-analyse.jpg"
|
||||
, $eventPath
|
||||
, $frame->{FrameId}
|
||||
);
|
||||
link( $frame->{capturePath}, $frame->{analysePath} )
|
||||
or Fatal( "Can't link ".$frame->{capturePath}
|
||||
." to ".$frame->{analysePath}.": $!"
|
||||
);
|
||||
setFileOwner( $frame->{analysePath} );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub addEventImage( $$ )
|
||||
sub addEventImage
|
||||
{
|
||||
my $event = shift;
|
||||
my $frame = shift;
|
||||
|
@ -455,7 +515,7 @@ sub addEventImage( $$ )
|
|||
# TBD
|
||||
}
|
||||
|
||||
sub updateEvent( $ )
|
||||
sub updateEvent
|
||||
{
|
||||
my $event = shift;
|
||||
|
||||
|
@ -467,7 +527,8 @@ sub updateEvent( $ )
|
|||
|
||||
my $dbh = zmDbConnect();
|
||||
|
||||
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} if ( $event->{Name} eq 'New Event' );
|
||||
$event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id}
|
||||
if ( $event->{Name} eq 'New Event' );
|
||||
|
||||
my %formats = (
|
||||
StartTime => 'from_unixtime(?)',
|
||||
|
@ -484,11 +545,13 @@ sub updateEvent( $ )
|
|||
my $sql = "update Events set ".join(',',@sets)." where Id = ?";
|
||||
push( @values, $event->{Id} );
|
||||
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( @values ) or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare sql '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( @values )
|
||||
or Fatal( "Can't execute sql '$sql': ".$sth->errstr() );
|
||||
}
|
||||
|
||||
sub deleteEventFiles( $;$ )
|
||||
sub deleteEventFiles
|
||||
{
|
||||
#
|
||||
# WARNING assumes running from events directory
|
||||
|
@ -541,7 +604,7 @@ sub deleteEventFiles( $;$ )
|
|||
}
|
||||
}
|
||||
|
||||
sub makePath( $;$ )
|
||||
sub makePath
|
||||
{
|
||||
my $path = shift;
|
||||
my $root = shift;
|
||||
|
@ -585,7 +648,7 @@ sub _testJSON
|
|||
$hasJSONAny = 1 if ( $result );
|
||||
}
|
||||
|
||||
sub _getJSONType( $ )
|
||||
sub _getJSONType
|
||||
{
|
||||
my $value = shift;
|
||||
return( 'null' ) unless( defined($value) );
|
||||
|
@ -596,9 +659,9 @@ sub _getJSONType( $ )
|
|||
return( 'string' );
|
||||
}
|
||||
|
||||
sub jsonEncode( $ );
|
||||
sub jsonEncode;
|
||||
|
||||
sub jsonEncode( $ )
|
||||
sub jsonEncode
|
||||
{
|
||||
my $value = shift;
|
||||
|
||||
|
@ -649,7 +712,7 @@ sub jsonEncode( $ )
|
|||
}
|
||||
}
|
||||
|
||||
sub jsonDecode( $ )
|
||||
sub jsonDecode
|
||||
{
|
||||
my $value = shift;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the debug definitions and functions used by the rest
|
||||
# This module contains the debug definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Logger;
|
||||
|
@ -126,6 +126,7 @@ our %priorities = (
|
|||
);
|
||||
|
||||
our $logger;
|
||||
our $LOGFILE;
|
||||
|
||||
sub new
|
||||
{
|
||||
|
@ -257,7 +258,12 @@ sub initialise( @ )
|
|||
{
|
||||
foreach my $target ( split( /\|/, $Config{ZM_LOG_DEBUG_TARGET} ) )
|
||||
{
|
||||
if ( $target eq $this->{id} || $target eq "_".$this->{id} || $target eq $this->{idRoot} || $target eq "_".$this->{idRoot} || $target eq "" )
|
||||
if ( $target eq $this->{id}
|
||||
|| $target eq "_".$this->{id}
|
||||
|| $target eq $this->{idRoot}
|
||||
|| $target eq "_".$this->{idRoot}
|
||||
|| $target eq ""
|
||||
)
|
||||
{
|
||||
if ( $Config{ZM_LOG_DEBUG_LEVEL} > NOLOG )
|
||||
{
|
||||
|
@ -286,11 +292,18 @@ sub initialise( @ )
|
|||
$this->{autoFlush} = $ENV{'LOG_FLUSH'}?1:0 if ( defined($ENV{'LOG_FLUSH'}) );
|
||||
|
||||
$this->{initialised} = !undef;
|
||||
|
||||
Debug( "LogOpts: level=".$codes{$this->{level}}."/".$codes{$this->{effectiveLevel}}.", screen=".$codes{$this->{termLevel}}.", database=".$codes{$this->{databaseLevel}}.", logfile=".$codes{$this->{fileLevel}}."->".$this->{logFile}.", syslog=".$codes{$this->{syslogLevel}} );
|
||||
|
||||
Debug( "LogOpts: level=".$codes{$this->{level}}
|
||||
."/".$codes{$this->{effectiveLevel}}
|
||||
.", screen=".$codes{$this->{termLevel}}
|
||||
.", database=".$codes{$this->{databaseLevel}}
|
||||
.", logfile=".$codes{$this->{fileLevel}}
|
||||
."->".$this->{logFile}
|
||||
.", syslog=".$codes{$this->{syslogLevel}}
|
||||
);
|
||||
}
|
||||
|
||||
sub terminate()
|
||||
sub terminate
|
||||
{
|
||||
my $this = shift;
|
||||
return unless ( $this->{initialised} );
|
||||
|
@ -300,7 +313,7 @@ sub terminate()
|
|||
$this->termLevel( NOLOG );
|
||||
}
|
||||
|
||||
sub reinitialise()
|
||||
sub reinitialise
|
||||
{
|
||||
my $this = shift;
|
||||
|
||||
|
@ -322,7 +335,7 @@ sub reinitialise()
|
|||
$this->databaseLevel( $databaseLevel ) if ( $databaseLevel > NOLOG );
|
||||
}
|
||||
|
||||
sub limit( $ )
|
||||
sub limit
|
||||
{
|
||||
my $this = shift;
|
||||
my $level = shift;
|
||||
|
@ -331,7 +344,7 @@ sub limit( $ )
|
|||
return( $level );
|
||||
}
|
||||
|
||||
sub getTargettedEnv( $ )
|
||||
sub getTargettedEnv
|
||||
{
|
||||
my $this = shift;
|
||||
my $name = shift;
|
||||
|
@ -354,7 +367,7 @@ sub getTargettedEnv( $ )
|
|||
return( $value );
|
||||
}
|
||||
|
||||
sub fetch()
|
||||
sub fetch
|
||||
{
|
||||
if ( !$logger )
|
||||
{
|
||||
|
@ -364,7 +377,7 @@ sub fetch()
|
|||
return( $logger );
|
||||
}
|
||||
|
||||
sub id( ;$ )
|
||||
sub id
|
||||
{
|
||||
my $this = shift;
|
||||
my $id = shift;
|
||||
|
@ -388,7 +401,7 @@ sub id( ;$ )
|
|||
return( $this->{id} );
|
||||
}
|
||||
|
||||
sub level( ;$ )
|
||||
sub level
|
||||
{
|
||||
my $this = shift;
|
||||
my $level = shift;
|
||||
|
@ -405,20 +418,20 @@ sub level( ;$ )
|
|||
return( $this->{level} );
|
||||
}
|
||||
|
||||
sub debugOn()
|
||||
sub debugOn
|
||||
{
|
||||
my $this = shift;
|
||||
return( $this->{effectiveLevel} >= DEBUG );
|
||||
}
|
||||
|
||||
sub trace( ;$ )
|
||||
sub trace
|
||||
{
|
||||
my $this = shift;
|
||||
$this->{trace} = $_[0] if ( @_ );
|
||||
return( $this->{trace} );
|
||||
}
|
||||
|
||||
sub termLevel( ;$ )
|
||||
sub termLevel
|
||||
{
|
||||
my $this = shift;
|
||||
my $termLevel = shift;
|
||||
|
@ -434,7 +447,7 @@ sub termLevel( ;$ )
|
|||
return( $this->{termLevel} );
|
||||
}
|
||||
|
||||
sub databaseLevel( ;$ )
|
||||
sub databaseLevel
|
||||
{
|
||||
my $this = shift;
|
||||
my $databaseLevel = shift;
|
||||
|
@ -451,23 +464,39 @@ sub databaseLevel( ;$ )
|
|||
|
||||
if ( defined($port) )
|
||||
{
|
||||
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$host.";port=".$port, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
||||
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.";host=".$host
|
||||
.";port=".$port
|
||||
, $Config{ZM_DB_USER}
|
||||
, $Config{ZM_DB_PASS}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}.";host=".$Config{ZM_DB_HOST}, $Config{ZM_DB_USER}, $Config{ZM_DB_PASS} );
|
||||
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
|
||||
.";host=".$Config{ZM_DB_HOST}
|
||||
, $Config{ZM_DB_USER}
|
||||
, $Config{ZM_DB_PASS}
|
||||
);
|
||||
}
|
||||
if ( !$this->{dbh} )
|
||||
{
|
||||
$databaseLevel = NOLOG;
|
||||
Error( "Unable to write log entries to DB, can't connect to database '".$Config{ZM_DB_NAME}."' on host '".$Config{ZM_DB_HOST}."'" );
|
||||
Error( "Unable to write log entries to DB, can't connect to database '"
|
||||
.$Config{ZM_DB_NAME}
|
||||
."' on host '"
|
||||
.$Config{ZM_DB_HOST}
|
||||
."'"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->{dbh}->{AutoCommit} = 1;
|
||||
Fatal( "Can't set AutoCommit on in database connection" ) unless( $this->{dbh}->{AutoCommit} );
|
||||
Fatal( "Can't set AutoCommit on in database connection" )
|
||||
unless( $this->{dbh}->{AutoCommit} );
|
||||
$this->{dbh}->{mysql_auto_reconnect} = 1;
|
||||
Fatal( "Can't set mysql_auto_reconnect on in database connection" ) unless( $this->{dbh}->{mysql_auto_reconnect} );
|
||||
Fatal( "Can't set mysql_auto_reconnect on in database connection" )
|
||||
unless( $this->{dbh}->{mysql_auto_reconnect} );
|
||||
$this->{dbh}->trace( 0 );
|
||||
}
|
||||
}
|
||||
|
@ -486,7 +515,7 @@ sub databaseLevel( ;$ )
|
|||
return( $this->{databaseLevel} );
|
||||
}
|
||||
|
||||
sub fileLevel( ;$ )
|
||||
sub fileLevel
|
||||
{
|
||||
my $this = shift;
|
||||
my $fileLevel = shift;
|
||||
|
@ -503,7 +532,7 @@ sub fileLevel( ;$ )
|
|||
return( $this->{fileLevel} );
|
||||
}
|
||||
|
||||
sub syslogLevel( ;$ )
|
||||
sub syslogLevel
|
||||
{
|
||||
my $this = shift;
|
||||
my $syslogLevel = shift;
|
||||
|
@ -520,19 +549,19 @@ sub syslogLevel( ;$ )
|
|||
return( $this->{syslogLevel} );
|
||||
}
|
||||
|
||||
sub openSyslog()
|
||||
sub openSyslog
|
||||
{
|
||||
my $this = shift;
|
||||
openlog( $this->{id}, "pid", "local1" );
|
||||
}
|
||||
|
||||
sub closeSyslog()
|
||||
sub closeSyslog
|
||||
{
|
||||
my $this = shift;
|
||||
#closelog();
|
||||
}
|
||||
|
||||
sub logFile( $ )
|
||||
sub logFile
|
||||
{
|
||||
my $this = shift;
|
||||
my $logFile = shift;
|
||||
|
@ -546,18 +575,21 @@ sub logFile( $ )
|
|||
}
|
||||
}
|
||||
|
||||
sub openFile()
|
||||
sub openFile
|
||||
{
|
||||
my $this = shift;
|
||||
if ( open( LOGFILE, ">>".$this->{logFile} ) )
|
||||
if ( open( $LOGFILE, ">>", $this->{logFile} ) )
|
||||
{
|
||||
LOGFILE->autoflush() if ( $this->{autoFlush} );
|
||||
$LOGFILE->autoflush() if ( $this->{autoFlush} );
|
||||
|
||||
my $webUid = (getpwnam( $Config{ZM_WEB_USER} ))[2];
|
||||
my $webGid = (getgrnam( $Config{ZM_WEB_GROUP} ))[2];
|
||||
if ( $> == 0 )
|
||||
{
|
||||
chown( $webUid, $webGid, $this->{logFile} ) or Fatal( "Can't change permissions on log file '".$this->{logFile}."': $!" )
|
||||
chown( $webUid, $webGid, $this->{logFile} )
|
||||
or Fatal( "Can't change permissions on log file '"
|
||||
.$this->{logFile}."': $!"
|
||||
)
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -567,13 +599,13 @@ sub openFile()
|
|||
}
|
||||
}
|
||||
|
||||
sub closeFile()
|
||||
sub closeFile
|
||||
{
|
||||
my $this = shift;
|
||||
close( LOGFILE ) if ( fileno(LOGFILE) );
|
||||
close( $LOGFILE ) if ( fileno($LOGFILE) );
|
||||
}
|
||||
|
||||
sub logPrint( $;$ )
|
||||
sub logPrint
|
||||
{
|
||||
my $this = shift;
|
||||
my $level = shift;
|
||||
|
@ -586,7 +618,17 @@ sub logPrint( $;$ )
|
|||
my $code = $codes{$level};
|
||||
|
||||
my ($seconds, $microseconds) = gettimeofday();
|
||||
my $message = sprintf( "%s.%06d %s[%d].%s [%s]", strftime( "%x %H:%M:%S", localtime( $seconds ) ), $microseconds, $this->{id}, $$, $code, $string );
|
||||
my $message = sprintf(
|
||||
"%s.%06d %s[%d].%s [%s]"
|
||||
, strftime( "%x %H:%M:%S"
|
||||
,localtime( $seconds )
|
||||
)
|
||||
, $microseconds
|
||||
, $this->{id}
|
||||
, $$
|
||||
, $code
|
||||
, $string
|
||||
);
|
||||
if ( $this->{trace} )
|
||||
{
|
||||
$message = Carp::shortmess( $message );
|
||||
|
@ -595,8 +637,9 @@ sub logPrint( $;$ )
|
|||
{
|
||||
$message = $message."\n";
|
||||
}
|
||||
syslog( $priorities{$level}, $code." [%s]", $string ) if ( $level <= $this->{syslogLevel} );
|
||||
print( LOGFILE $message ) if ( $level <= $this->{fileLevel} );
|
||||
syslog( $priorities{$level}, $code." [%s]", $string )
|
||||
if ( $level <= $this->{syslogLevel} );
|
||||
print( $LOGFILE $message ) if ( $level <= $this->{fileLevel} );
|
||||
if ( $level <= $this->{databaseLevel} )
|
||||
{
|
||||
my $sql = "insert into Logs ( TimeKey, Component, Pid, Level, Code, Message, File, Line ) values ( ?, ?, ?, ?, ?, ?, ?, NULL )";
|
||||
|
@ -606,7 +649,14 @@ sub logPrint( $;$ )
|
|||
$this->{databaseLevel} = NOLOG;
|
||||
Fatal( "Can't prepare log entry '$sql': ".$this->{dbh}->errstr() );
|
||||
}
|
||||
my $res = $this->{sth}->execute( $seconds+($microseconds/1000000.0), $this->{id}, $$, $level, $code, $string, $this->{fileName} );
|
||||
my $res = $this->{sth}->execute( $seconds+($microseconds/1000000.0)
|
||||
, $this->{id}
|
||||
, $$
|
||||
, $level
|
||||
, $code
|
||||
, $string
|
||||
, $this->{fileName}
|
||||
);
|
||||
if ( !$res )
|
||||
{
|
||||
$this->{databaseLevel} = NOLOG;
|
||||
|
@ -624,7 +674,7 @@ sub logInit( ;@ )
|
|||
$logger->initialise( %options );
|
||||
}
|
||||
|
||||
sub logReinit()
|
||||
sub logReinit
|
||||
{
|
||||
fetch()->reinitialise();
|
||||
}
|
||||
|
@ -636,7 +686,7 @@ sub logTerm
|
|||
$logger = undef;
|
||||
}
|
||||
|
||||
sub logHupHandler()
|
||||
sub logHupHandler
|
||||
{
|
||||
my $savedErrno = $!;
|
||||
return unless( $logger );
|
||||
|
@ -645,47 +695,47 @@ sub logHupHandler()
|
|||
$! = $savedErrno;
|
||||
}
|
||||
|
||||
sub logSetSignal()
|
||||
sub logSetSignal
|
||||
{
|
||||
$SIG{HUP} = \&logHupHandler;
|
||||
}
|
||||
|
||||
sub logClearSignal()
|
||||
sub logClearSignal
|
||||
{
|
||||
$SIG{HUP} = 'DEFAULT';
|
||||
}
|
||||
|
||||
sub logLevel( ;$ )
|
||||
sub logLevel
|
||||
{
|
||||
return( fetch()->level( @_ ) );
|
||||
}
|
||||
|
||||
sub logDebugging()
|
||||
sub logDebugging
|
||||
{
|
||||
return( fetch()->debugOn() );
|
||||
}
|
||||
|
||||
sub logTermLevel( ;$ )
|
||||
sub logTermLevel
|
||||
{
|
||||
return( fetch()->termLevel( @_ ) );
|
||||
}
|
||||
|
||||
sub logDatabaseLevel( ;$ )
|
||||
sub logDatabaseLevel
|
||||
{
|
||||
return( fetch()->databaseLevel( @_ ) );
|
||||
}
|
||||
|
||||
sub logFileLevel( ;$ )
|
||||
sub logFileLevel
|
||||
{
|
||||
return( fetch()->fileLevel( @_ ) );
|
||||
}
|
||||
|
||||
sub logSyslogLevel( ;$ )
|
||||
sub logSyslogLevel
|
||||
{
|
||||
return( fetch()->syslogLevel( @_ ) );
|
||||
}
|
||||
|
||||
sub Mark( ;$$ )
|
||||
sub Mark
|
||||
{
|
||||
my $level = shift;
|
||||
$level = DEBUG unless( defined($level) );
|
||||
|
@ -693,7 +743,7 @@ sub Mark( ;$$ )
|
|||
fetch()->logPrint( $level, $tag );
|
||||
}
|
||||
|
||||
sub Dump( \$;$ )
|
||||
sub Dump
|
||||
{
|
||||
my $var = shift;
|
||||
my $label = shift;
|
||||
|
@ -756,11 +806,19 @@ ZoneMinder::Logger - ZoneMinder Logger module
|
|||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The ZoneMinder:Logger module contains the common debug and error reporting routines used by the ZoneMinder scripts.
|
||||
The ZoneMinder:Logger module contains the common debug and error reporting
|
||||
routines used by the ZoneMinder scripts.
|
||||
|
||||
To use debug in your scripts you need to include this module, and call logInit. Thereafter you can sprinkle Debug or Error calls etc throughout the code safe in the knowledge that they will be reported to your error log, and possibly the syslogger, in a meaningful and consistent format.
|
||||
To use debug in your scripts you need to include this module, and call
|
||||
logInit. Thereafter you can sprinkle Debug or Error calls etc throughout
|
||||
the code safe in the knowledge that they will be reported to your error
|
||||
log, and possibly the syslogger, in a meaningful and consistent format.
|
||||
|
||||
Debug is discussed in terms of levels where 1 and above (currently only 1 for scripts) is considered debug, 0 is considered as informational, -1 is a warning, -2 is an error and -3 is a fatal error or panic. Where levels are mentioned below as thresholds the value given and anything with a lower level (ie. more serious) will be included.
|
||||
Debug is discussed in terms of levels where 1 and above (currently only 1
|
||||
for scripts) is considered debug, 0 is considered as informational, -1 is a
|
||||
warning, -2 is an error and -3 is a fatal error or panic. Where levels are
|
||||
mentioned below as thresholds the value given and anything with a lower
|
||||
level (ie. more serious) will be included.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
|
@ -768,7 +826,12 @@ Debug is discussed in terms of levels where 1 and above (currently only 1 for sc
|
|||
|
||||
=item logInit ( $id, %options );
|
||||
|
||||
Initialises the debug and prepares the logging for forthcoming operations. If not called explicitly it will be called by the first debug call in your script, but with default (and probably meaningless) options. The only compulsory arguments are $id which must be a string that will identify debug coming from this script in mixed logs. Other options may be provided as below,
|
||||
Initialises the debug and prepares the logging for forthcoming operations.
|
||||
If not called explicitly it will be called by the first debug call in your
|
||||
script, but with default (and probably meaningless) options. The only
|
||||
compulsory arguments are $id which must be a string that will identify
|
||||
debug coming from this script in mixed logs. Other options may be provided
|
||||
as below,
|
||||
|
||||
Option Default Description
|
||||
--------- --------- -----------
|
||||
|
@ -805,27 +868,41 @@ These methods can be used to get and set the current settings as defined in logI
|
|||
|
||||
=item Debug( $string );
|
||||
|
||||
This method will output a debug message if the current debug level permits it, otherwise does nothing. This message will be tagged with the DBG string in the logs.
|
||||
This method will output a debug message if the current debug level permits
|
||||
it, otherwise does nothing. This message will be tagged with the DBG string
|
||||
in the logs.
|
||||
|
||||
=item Info( $string );
|
||||
|
||||
This method will output an informational message if the current debug level permits it, otherwise does nothing. This message will be tagged with the INF string in the logs.
|
||||
This method will output an informational message if the current debug level
|
||||
permits it, otherwise does nothing. This message will be tagged with the
|
||||
INF string in the logs.
|
||||
|
||||
=item Warning( $string );
|
||||
|
||||
This method will output a warning message if the current debug level permits it, otherwise does nothing. This message will be tagged with the WAR string in the logs.
|
||||
This method will output a warning message if the current debug level
|
||||
permits it, otherwise does nothing. This message will be tagged with the
|
||||
WAR string in the logs.
|
||||
|
||||
=item Error( $string );
|
||||
|
||||
This method will output an error message if the current debug level permits it, otherwise does nothing. This message will be tagged with the ERR string in the logs.
|
||||
This method will output an error message if the current debug level permits
|
||||
it, otherwise does nothing. This message will be tagged with the ERR string
|
||||
in the logs.
|
||||
|
||||
=item Fatal( $string );
|
||||
|
||||
This method will output a fatal error message and then die if the current debug level permits it, otherwise does nothing. This message will be tagged with the FAT string in the logs.
|
||||
This method will output a fatal error message and then die if the current
|
||||
debug level permits it, otherwise does nothing. This message will be tagged
|
||||
with the FAT string in the logs.
|
||||
|
||||
=item Panic( $string );
|
||||
|
||||
This method will output a panic error message and then die with a stack trace if the current debug level permits it, otherwise does nothing. This message will be tagged with the PNC string in the logs.
|
||||
This method will output a panic error message and then die with a stack
|
||||
trace if the current debug level permits it, otherwise does nothing. This
|
||||
message will be tagged with the PNC string in the logs.
|
||||
|
||||
=back
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
|
@ -841,7 +918,8 @@ The :all tag will export all above symbols.
|
|||
Carp
|
||||
Sys::Syslog
|
||||
|
||||
The ZoneMinder README file Troubleshooting section for an extended discussion on the use and configuration of syslog with ZoneMinder.
|
||||
The ZoneMinder README file Troubleshooting section for an extended
|
||||
discussion on the use and configuration of syslog with ZoneMinder.
|
||||
|
||||
http://www.zoneminder.com
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,18 +36,18 @@ our @ISA = qw(Exporter ZoneMinder::Base);
|
|||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
zmMemKey
|
||||
zmMemAttach
|
||||
zmMemDetach
|
||||
zmMemGet
|
||||
zmMemPut
|
||||
zmMemClean
|
||||
) ],
|
||||
'functions' => [ qw(
|
||||
zmMemKey
|
||||
zmMemAttach
|
||||
zmMemDetach
|
||||
zmMemGet
|
||||
zmMemPut
|
||||
zmMemClean
|
||||
) ],
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
|
@ -68,117 +68,131 @@ use ZoneMinder::Logger qw(:all);
|
|||
|
||||
use Sys::Mmap;
|
||||
|
||||
sub zmMemKey( $ )
|
||||
sub zmMemKey
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $monitor = shift;
|
||||
return( defined($monitor->{MMapAddr})?$monitor->{MMapAddr}:undef );
|
||||
}
|
||||
|
||||
sub zmMemAttach( $$ )
|
||||
sub zmMemAttach
|
||||
{
|
||||
my ( $monitor, $size ) = @_;
|
||||
if ( ! $size ) {
|
||||
Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" );
|
||||
return( undef );
|
||||
}
|
||||
if ( !defined($monitor->{MMapAddr}) )
|
||||
{
|
||||
my ( $monitor, $size ) = @_;
|
||||
if ( ! $size ) {
|
||||
Error( "No size passed to zmMemAttach for monitor $$monitor{Id}\n" );
|
||||
return( undef );
|
||||
}
|
||||
if ( !defined($monitor->{MMapAddr}) )
|
||||
{
|
||||
|
||||
my $mmap_file = $Config{ZM_PATH_MAP}."/zm.mmap.".$monitor->{Id};
|
||||
if ( ! -e $mmap_file ) {
|
||||
Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running.", $mmap_file ) );
|
||||
return ( undef );
|
||||
}
|
||||
if ( ! -e $mmap_file ) {
|
||||
Error( sprintf( "Memory map file '%s' does not exist. zmc might not be running."
|
||||
, $mmap_file
|
||||
)
|
||||
);
|
||||
return ( undef );
|
||||
}
|
||||
|
||||
my $mmap_file_size = -s $mmap_file;
|
||||
my $mmap_file_size = -s $mmap_file;
|
||||
|
||||
if ( $mmap_file_size < $size ) {
|
||||
Error( sprintf( "Memory map file '%s' should have been %d but was instead %d", $mmap_file, $size, $mmap_file_size ) );
|
||||
return ( undef );
|
||||
}
|
||||
if ( !open( MMAP, "+<".$mmap_file ) )
|
||||
if ( $mmap_file_size < $size ) {
|
||||
Error( sprintf( "Memory map file '%s' should have been %d but was instead %d"
|
||||
, $mmap_file
|
||||
, $size
|
||||
, $mmap_file_size
|
||||
)
|
||||
);
|
||||
return ( undef );
|
||||
}
|
||||
if ( !open( MMAP, "+<", $mmap_file ) )
|
||||
{
|
||||
Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) );
|
||||
return( undef );
|
||||
Error( sprintf( "Can't open memory map file '%s': $!\n", $mmap_file ) );
|
||||
return( undef );
|
||||
}
|
||||
my $mmap = undef;
|
||||
my $mmap_addr = mmap( $mmap, $size, PROT_READ|PROT_WRITE, MAP_SHARED, \*MMAP );
|
||||
if ( !$mmap_addr || !$mmap )
|
||||
{
|
||||
Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) );
|
||||
close( MMAP );
|
||||
return( undef );
|
||||
Error( sprintf( "Can't mmap to file '%s': $!\n", $mmap_file ) );
|
||||
close( MMAP );
|
||||
return( undef );
|
||||
}
|
||||
$monitor->{MMapHandle} = \*MMAP;
|
||||
$monitor->{MMapAddr} = $mmap_addr;
|
||||
$monitor->{MMap} = \$mmap;
|
||||
}
|
||||
return( !undef );
|
||||
$monitor->{MMapHandle} = \*MMAP;
|
||||
$monitor->{MMapAddr} = $mmap_addr;
|
||||
$monitor->{MMap} = \$mmap;
|
||||
}
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
sub zmMemDetach( $ )
|
||||
sub zmMemDetach
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $monitor = shift;
|
||||
|
||||
if ( $monitor->{MMap} )
|
||||
{
|
||||
if ( ! munmap( ${$monitor->{MMap}} ) ) {
|
||||
Warn( "Unable to munmap for monitor $$monitor{Id}\n");
|
||||
}
|
||||
delete $monitor->{MMap};
|
||||
Warn( "Unable to munmap for monitor $$monitor{Id}\n");
|
||||
}
|
||||
delete $monitor->{MMap};
|
||||
}
|
||||
if ( $monitor->{MMapAddr} )
|
||||
{
|
||||
delete $monitor->{MMapAddr};
|
||||
delete $monitor->{MMapAddr};
|
||||
}
|
||||
if ( $monitor->{MMapHandle} )
|
||||
{
|
||||
close( $monitor->{MMapHandle} );
|
||||
delete $monitor->{MMapHandle};
|
||||
delete $monitor->{MMapHandle};
|
||||
}
|
||||
}
|
||||
|
||||
sub zmMemGet( $$$ )
|
||||
sub zmMemGet
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
|
||||
my $mmap = $monitor->{MMap};
|
||||
my $mmap = $monitor->{MMap};
|
||||
if ( !$mmap || !$$mmap )
|
||||
{
|
||||
Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?", $monitor->{Id} ) );
|
||||
Error( sprintf( "Can't read from mapped memory for monitor '%d', gone away?"
|
||||
, $monitor->{Id}
|
||||
)
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
my $data = substr( $$mmap, $offset, $size );
|
||||
my $data = substr( $$mmap, $offset, $size );
|
||||
return( $data );
|
||||
}
|
||||
|
||||
sub zmMemPut( $$$$ )
|
||||
sub zmMemPut
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $data = shift;
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $data = shift;
|
||||
|
||||
my $mmap = $monitor->{MMap};
|
||||
my $mmap = $monitor->{MMap};
|
||||
if ( !$mmap || !$$mmap )
|
||||
{
|
||||
Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?", $monitor->{Id} ) );
|
||||
Error( sprintf( "Can't write mapped memory for monitor '%d', gone away?"
|
||||
, $monitor->{Id}
|
||||
)
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
substr( $$mmap, $offset, $size ) = $data;
|
||||
return( !undef );
|
||||
substr( $$mmap, $offset, $size ) = $data;
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
sub zmMemClean
|
||||
{
|
||||
Debug( "Removing memory map files\n" );
|
||||
Debug( "Removing memory map files\n" );
|
||||
my $mapPath = $Config{ZM_PATH_MAP}."/zm.mmap.*";
|
||||
foreach my $mapFile( glob( $mapPath ) )
|
||||
{
|
||||
( $mapFile ) = $mapFile =~ /^(.+)$/;
|
||||
Debug( "Removing memory map file '$mapFile'\n" );
|
||||
Debug( "Removing memory map file '$mapFile'\n" );
|
||||
unlink( $mapFile );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Memory::Shared;
|
||||
|
@ -39,18 +39,18 @@ eval 'sub IPC_CREAT {0001000}' unless defined &IPC_CREAT;
|
|||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
'functions' => [ qw(
|
||||
zmMemKey
|
||||
zmMemAttach
|
||||
zmMemDetach
|
||||
zmMemGet
|
||||
zmMemPut
|
||||
zmMemClean
|
||||
) ],
|
||||
) ],
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
|
@ -69,82 +69,98 @@ our $VERSION = $ZoneMinder::Base::VERSION;
|
|||
use ZoneMinder::Config qw(:all);
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
|
||||
sub zmMemKey( $ )
|
||||
sub zmMemKey
|
||||
{
|
||||
my $monitor = shift;
|
||||
return( defined($monitor->{ShmKey})?$monitor->{ShmKey}:undef );
|
||||
my $monitor = shift;
|
||||
return( defined($monitor->{ShmKey})?$monitor->{ShmKey}:undef );
|
||||
}
|
||||
|
||||
sub zmMemAttach( $$ )
|
||||
sub zmMemAttach
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $size = shift;
|
||||
if ( !defined($monitor->{ShmId}) )
|
||||
{
|
||||
my $shm_key = (hex($Config{ZM_SHM_KEY})&0xffff0000)|$monitor->{Id};
|
||||
my $shm_id = shmget( $shm_key, $size, &IPC_CREAT | 0777 );
|
||||
if ( !defined($shm_id) )
|
||||
{
|
||||
Error( sprintf( "Can't get shared memory id '%x', %d: $!\n", $shm_key, $monitor->{Id} ) );
|
||||
return( undef );
|
||||
}
|
||||
$monitor->{ShmKey} = $shm_key;
|
||||
$monitor->{ShmId} = $shm_id;
|
||||
}
|
||||
return( !undef );
|
||||
my $monitor = shift;
|
||||
my $size = shift;
|
||||
if ( !defined($monitor->{ShmId}) )
|
||||
{
|
||||
my $shm_key = (hex($Config{ZM_SHM_KEY})&0xffff0000)|$monitor->{Id};
|
||||
my $shm_id = shmget( $shm_key, $size, &IPC_CREAT | 0777 );
|
||||
if ( !defined($shm_id) )
|
||||
{
|
||||
Error( sprintf( "Can't get shared memory id '%x', %d: $!\n"
|
||||
, $shm_key
|
||||
, $monitor->{Id}
|
||||
)
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
$monitor->{ShmKey} = $shm_key;
|
||||
$monitor->{ShmId} = $shm_id;
|
||||
}
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
sub zmMemDetach( $ )
|
||||
sub zmMemDetach
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $monitor = shift;
|
||||
|
||||
delete $monitor->{ShmId};
|
||||
delete $monitor->{ShmId};
|
||||
}
|
||||
|
||||
sub zmMemGet( $$$ )
|
||||
sub zmMemGet
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
|
||||
my $shm_key = $monitor->{ShmKey};
|
||||
my $shm_id = $monitor->{ShmId};
|
||||
|
||||
my $shm_key = $monitor->{ShmKey};
|
||||
my $shm_id = $monitor->{ShmId};
|
||||
|
||||
my $data;
|
||||
if ( !shmread( $shm_id, $data, $offset, $size ) )
|
||||
{
|
||||
Error( sprintf( "Can't read from shared memory '%x/%d': $!", $shm_key, $shm_id ) );
|
||||
Error( sprintf( "Can't read from shared memory '%x/%d': $!"
|
||||
, $shm_key
|
||||
, $shm_id
|
||||
)
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
return( $data );
|
||||
return( $data );
|
||||
}
|
||||
|
||||
sub zmMemPut( $$$$ )
|
||||
sub zmMemPut
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $data = shift;
|
||||
my $monitor = shift;
|
||||
my $offset = shift;
|
||||
my $size = shift;
|
||||
my $data = shift;
|
||||
|
||||
my $shm_key = $monitor->{ShmKey};
|
||||
my $shm_id = $monitor->{ShmId};
|
||||
|
||||
my $shm_key = $monitor->{ShmKey};
|
||||
my $shm_id = $monitor->{ShmId};
|
||||
|
||||
if ( !shmwrite( $shm_id, $data, $offset, $size ) )
|
||||
{
|
||||
Error( sprintf( "Can't write to shared memory '%x/%d': $!", $shm_key, $shm_id ) );
|
||||
Error( sprintf( "Can't write to shared memory '%x/%d': $!"
|
||||
, $shm_key
|
||||
, $shm_id
|
||||
)
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
return( !undef );
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
sub zmMemClean
|
||||
{
|
||||
Debug( "Removing shared memory\n" );
|
||||
# Find ZoneMinder shared memory
|
||||
my $command = "ipcs -m | grep '^".substr( sprintf( "0x%x", hex($Config{ZM_SHM_KEY}) ), 0, -2 )."'";
|
||||
my $command = "ipcs -m | grep '^"
|
||||
.substr( sprintf( "0x%x", hex($Config{ZM_SHM_KEY}) ), 0, -2 )
|
||||
."'"
|
||||
;
|
||||
Debug( "Checking for shared memory with '$command'\n" );
|
||||
open( CMD, "$command |" ) or Fatal( "Can't execute '$command': $!" );
|
||||
while( <CMD> )
|
||||
open( my $CMD, '<', "$command |" )
|
||||
or Fatal( "Can't execute '$command': $!" );
|
||||
while( <$CMD> )
|
||||
{
|
||||
chomp;
|
||||
my ( $key, $id ) = split( /\s+/ );
|
||||
|
@ -156,7 +172,7 @@ sub zmMemClean
|
|||
qx( $command );
|
||||
}
|
||||
}
|
||||
close( CMD );
|
||||
close( $CMD );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -46,53 +46,53 @@ our $AUTOLOAD;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $self = {};
|
||||
$self->{readable} = !undef;
|
||||
$self->{writeable} = !undef;
|
||||
$self->{selectable} = undef;
|
||||
$self->{state} = 'closed';
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my $self = {};
|
||||
$self->{readable} = !undef;
|
||||
$self->{writeable} = !undef;
|
||||
$self->{selectable} = undef;
|
||||
$self->{state} = 'closed';
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub clone
|
||||
{
|
||||
my $self = shift;
|
||||
my $clone = { %$self };
|
||||
bless $clone, ref $self;
|
||||
my $self = shift;
|
||||
my $clone = { %$self };
|
||||
bless $clone, ref $self;
|
||||
}
|
||||
|
||||
sub open()
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
||||
croak( "Abstract base class method called for object of class $class" );
|
||||
my $self = shift;
|
||||
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
||||
croak( "Abstract base class method called for object of class $class" );
|
||||
}
|
||||
|
||||
sub close()
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
||||
croak( "Abstract base class method called for object of class $class" );
|
||||
my $self = shift;
|
||||
my $class = ref($self) or croak( "Can't get class for non object $self" );
|
||||
croak( "Abstract base class method called for object of class $class" );
|
||||
}
|
||||
|
||||
sub getState()
|
||||
sub getState
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{state} );
|
||||
my $self = shift;
|
||||
return( $self->{state} );
|
||||
}
|
||||
|
||||
sub isOpen()
|
||||
sub isOpen
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{state} eq "open" );
|
||||
my $self = shift;
|
||||
return( $self->{state} eq "open" );
|
||||
}
|
||||
|
||||
sub isConnected()
|
||||
sub isConnected
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{state} eq "connected" );
|
||||
my $self = shift;
|
||||
return( $self->{state} eq "connected" );
|
||||
}
|
||||
|
||||
sub DESTROY
|
||||
|
@ -101,15 +101,15 @@ sub DESTROY
|
|||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( !exists($self->{$name}) )
|
||||
{
|
||||
croak( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
return( $self->{$name} );
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( !exists($self->{$name}) )
|
||||
{
|
||||
croak( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
return( $self->{$name} );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -48,23 +48,23 @@ use Fcntl;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel::Handle->new;
|
||||
$self->{path} = $params{path};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel::Handle->new;
|
||||
$self->{path} = $params{path};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub open()
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
local *sfh;
|
||||
#sysopen( *sfh, $conn->{path}, O_NONBLOCK|O_RDONLY ) or croak( "Can't sysopen: $!" );
|
||||
#open( *sfh, "<".$conn->{path} ) or croak( "Can't open: $!" );
|
||||
open( *sfh, "+<".$self->{path} ) or croak( "Can't open: $!" );
|
||||
$self->{state} = 'open';
|
||||
$self->{handle} = *sfh;
|
||||
my $self = shift;
|
||||
local *sfh;
|
||||
#sysopen( *sfh, $conn->{path}, O_NONBLOCK|O_RDONLY ) or croak( "Can't sysopen: $!" );
|
||||
#open( *sfh, "<".$conn->{path} ) or croak( "Can't open: $!" );
|
||||
open( *sfh, "+<", $self->{path} ) or croak( "Can't open: $!" );
|
||||
$self->{state} = 'open';
|
||||
$self->{handle} = *sfh;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -46,12 +46,12 @@ use POSIX;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $port = shift;
|
||||
my $self = ZoneMinder::Trigger::Channel->new();
|
||||
$self->{handle} = undef;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my $port = shift;
|
||||
my $self = ZoneMinder::Trigger::Channel->new();
|
||||
$self->{handle} = undef;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub spawns
|
||||
|
@ -59,45 +59,51 @@ sub spawns
|
|||
return( undef );
|
||||
}
|
||||
|
||||
sub close()
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
close( $self->{handle} );
|
||||
$self->{state} = 'closed';
|
||||
$self->{handle} = undef;
|
||||
my $self = shift;
|
||||
close( $self->{handle} );
|
||||
$self->{state} = 'closed';
|
||||
$self->{handle} = undef;
|
||||
}
|
||||
|
||||
sub read()
|
||||
sub read
|
||||
{
|
||||
my $self = shift;
|
||||
my $buffer;
|
||||
my $nbytes = sysread( $self->{handle}, $buffer, POSIX::BUFSIZ );
|
||||
if ( !$nbytes )
|
||||
{
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Read '$buffer' ($nbytes bytes)\n" );
|
||||
return( $buffer );
|
||||
my $self = shift;
|
||||
my $buffer;
|
||||
my $nbytes = sysread( $self->{handle}, $buffer, POSIX::BUFSIZ );
|
||||
if ( !$nbytes )
|
||||
{
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Read '$buffer' ($nbytes bytes)\n" );
|
||||
return( $buffer );
|
||||
}
|
||||
|
||||
sub write()
|
||||
sub write
|
||||
{
|
||||
my $self = shift;
|
||||
my $buffer = shift;
|
||||
my $nbytes = syswrite( $self->{handle}, $buffer );
|
||||
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".($nbytes?$nbytes:'undefined').": $!\n" );
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
||||
return( !undef );
|
||||
my $self = shift;
|
||||
my $buffer = shift;
|
||||
my $nbytes = syswrite( $self->{handle}, $buffer );
|
||||
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer
|
||||
.", expected "
|
||||
.length($buffer)
|
||||
." bytes, sent "
|
||||
.($nbytes?$nbytes:'undefined')
|
||||
.": $!\n"
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
sub fileno()
|
||||
sub fileno
|
||||
{
|
||||
my $self = shift;
|
||||
return( defined($self->{handle})?fileno($self->{handle}):-1 );
|
||||
my $self = shift;
|
||||
return( defined($self->{handle})?fileno($self->{handle}):-1 );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -48,44 +48,45 @@ use Socket;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel::Spawning->new();
|
||||
$self->{selectable} = !undef;
|
||||
$self->{port} = $params{port};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel::Spawning->new();
|
||||
$self->{selectable} = !undef;
|
||||
$self->{port} = $params{port};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub open()
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
local *sfh;
|
||||
my $saddr = sockaddr_in( $self->{port}, INADDR_ANY );
|
||||
socket( *sfh, PF_INET, SOCK_STREAM, getprotobyname('tcp') ) or croak( "Can't open socket: $!" );
|
||||
setsockopt( *sfh, SOL_SOCKET, SO_REUSEADDR, 1 );
|
||||
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
||||
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
||||
$self->{state} = 'open';
|
||||
$self->{handle} = *sfh;
|
||||
my $self = shift;
|
||||
local *sfh;
|
||||
my $saddr = sockaddr_in( $self->{port}, INADDR_ANY );
|
||||
socket( *sfh, PF_INET, SOCK_STREAM, getprotobyname('tcp') )
|
||||
or croak( "Can't open socket: $!" );
|
||||
setsockopt( *sfh, SOL_SOCKET, SO_REUSEADDR, 1 );
|
||||
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
||||
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
||||
$self->{state} = 'open';
|
||||
$self->{handle} = *sfh;
|
||||
}
|
||||
|
||||
sub _spawn( $ )
|
||||
sub _spawn
|
||||
{
|
||||
my $self = shift;
|
||||
my $new_handle = shift;
|
||||
my $clone = $self->clone();
|
||||
$clone->{handle} = $new_handle;
|
||||
$clone->{state} = 'connected';
|
||||
return( $clone );
|
||||
my $self = shift;
|
||||
my $new_handle = shift;
|
||||
my $clone = $self->clone();
|
||||
$clone->{handle} = $new_handle;
|
||||
$clone->{state} = 'connected';
|
||||
return( $clone );
|
||||
}
|
||||
|
||||
sub accept()
|
||||
sub accept
|
||||
{
|
||||
my $self = shift;
|
||||
local *cfh;
|
||||
my $paddr = accept( *cfh, $self->{handle} );
|
||||
return( $self->_spawn( *cfh ) );
|
||||
my $self = shift;
|
||||
local *cfh;
|
||||
my $paddr = accept( *cfh, $self->{handle} );
|
||||
return( $self->_spawn( *cfh ) );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -46,64 +46,70 @@ use Device::SerialPort;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel->new;
|
||||
$self->{path} = $params{path};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel->new;
|
||||
$self->{path} = $params{path};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub open()
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
my $device = new Device::SerialPort( $self->{path} );
|
||||
$device->baudrate(9600);
|
||||
$device->databits(8);
|
||||
$device->parity('none');
|
||||
$device->stopbits(1);
|
||||
$device->handshake('none');
|
||||
my $self = shift;
|
||||
my $device = new Device::SerialPort( $self->{path} );
|
||||
$device->baudrate(9600);
|
||||
$device->databits(8);
|
||||
$device->parity('none');
|
||||
$device->stopbits(1);
|
||||
$device->handshake('none');
|
||||
|
||||
$device->read_const_time(50);
|
||||
$device->read_char_time(10);
|
||||
$device->read_const_time(50);
|
||||
$device->read_char_time(10);
|
||||
|
||||
$self->{device} = $device;
|
||||
$self->{state} = 'open';
|
||||
$self->{state} = 'connected';
|
||||
$self->{device} = $device;
|
||||
$self->{state} = 'open';
|
||||
$self->{state} = 'connected';
|
||||
}
|
||||
|
||||
sub close()
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{device}->close();
|
||||
$self->{state} = 'closed';
|
||||
my $self = shift;
|
||||
$self->{device}->close();
|
||||
$self->{state} = 'closed';
|
||||
}
|
||||
|
||||
sub read()
|
||||
sub read
|
||||
{
|
||||
my $self = shift;
|
||||
my $buffer = $self->{device}->lookfor();
|
||||
if ( !$buffer || !length($buffer) )
|
||||
{
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Read '$buffer' (".length($buffer)." bytes)\n" );
|
||||
return( $buffer );
|
||||
my $self = shift;
|
||||
my $buffer = $self->{device}->lookfor();
|
||||
if ( !$buffer || !length($buffer) )
|
||||
{
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Read '$buffer' (".length($buffer)." bytes)\n" );
|
||||
return( $buffer );
|
||||
}
|
||||
|
||||
sub write()
|
||||
sub write
|
||||
{
|
||||
my $self = shift;
|
||||
my $buffer = shift;
|
||||
my $nbytes = $self->{device}->write( $buffer );
|
||||
$self->{device}->write_drain();
|
||||
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer.", expected ".length($buffer)." bytes, sent ".$nbytes.": $!\n" );
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
||||
return( !undef );
|
||||
my $self = shift;
|
||||
my $buffer = shift;
|
||||
my $nbytes = $self->{device}->write( $buffer );
|
||||
$self->{device}->write_drain();
|
||||
if ( !defined( $nbytes) || $nbytes < length($buffer) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer
|
||||
.", expected "
|
||||
.length($buffer)
|
||||
." bytes, sent "
|
||||
.$nbytes
|
||||
.": $!\n"
|
||||
);
|
||||
return( undef );
|
||||
}
|
||||
Debug( "Wrote '$buffer' ($nbytes bytes)\n" );
|
||||
return( !undef );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -45,12 +45,12 @@ use ZoneMinder::Logger qw(:all);
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $port = shift;
|
||||
my $self = ZoneMinder::Trigger::Channel::Handle->new();
|
||||
$self->{spawns} = !undef;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my $port = shift;
|
||||
my $self = ZoneMinder::Trigger::Channel::Handle->new();
|
||||
$self->{spawns} = !undef;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub spawns
|
||||
|
|
|
@ -48,28 +48,28 @@ use Socket;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel->new;
|
||||
$self->{selectable} = !undef;
|
||||
$self->{path} = $params{path};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = ZoneMinder::Trigger::Channel->new;
|
||||
$self->{selectable} = !undef;
|
||||
$self->{path} = $params{path};
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub open()
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
local *sfh;
|
||||
unlink( $self->{path} );
|
||||
my $saddr = sockaddr_un( $self->{path} );
|
||||
socket( *sfh, PF_UNIX, SOCK_STREAM, 0 ) or croak( "Can't open socket: $!" );
|
||||
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
||||
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
||||
$self->{handle} = *sfh;
|
||||
my $self = shift;
|
||||
local *sfh;
|
||||
unlink( $self->{path} );
|
||||
my $saddr = sockaddr_un( $self->{path} );
|
||||
socket( *sfh, PF_UNIX, SOCK_STREAM, 0 ) or croak( "Can't open socket: $!" );
|
||||
bind( *sfh, $saddr ) or croak( "Can't bind: $!" );
|
||||
listen( *sfh, SOMAXCONN ) or croak( "Can't listen: $!" );
|
||||
$self->{handle} = *sfh;
|
||||
}
|
||||
|
||||
sub _spawn( $ )
|
||||
sub _spawn
|
||||
{
|
||||
my $self = shift;
|
||||
my $new_handle = shift;
|
||||
|
@ -79,7 +79,7 @@ sub _spawn( $ )
|
|||
return( $clone );
|
||||
}
|
||||
|
||||
sub accept()
|
||||
sub accept
|
||||
{
|
||||
my $self = shift;
|
||||
local *cfh;
|
||||
|
|
|
@ -46,115 +46,121 @@ our $AUTOLOAD;
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = {};
|
||||
$self->{name} = $params{name};
|
||||
$self->{channel} = $params{channel};
|
||||
$self->{input} = $params{mode} =~ /r/i;
|
||||
$self->{output} = $params{mode} =~ /w/i;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my %params = @_;
|
||||
my $self = {};
|
||||
$self->{name} = $params{name};
|
||||
$self->{channel} = $params{channel};
|
||||
$self->{input} = $params{mode} =~ /r/i;
|
||||
$self->{output} = $params{mode} =~ /w/i;
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub clone
|
||||
{
|
||||
my $self = shift;
|
||||
my $clone = { %$self };
|
||||
bless $clone, ref $self;
|
||||
return( $clone );
|
||||
my $self = shift;
|
||||
my $clone = { %$self };
|
||||
bless $clone, ref $self;
|
||||
return( $clone );
|
||||
}
|
||||
|
||||
sub spawns
|
||||
{
|
||||
my $self = shift;
|
||||
my $self = shift;
|
||||
return( $self->{channel}->spawns() );
|
||||
}
|
||||
|
||||
sub _spawn( $ )
|
||||
sub _spawn
|
||||
{
|
||||
my $self = shift;
|
||||
my $new_channel = shift;
|
||||
my $clone = $self->clone();
|
||||
$clone->{channel} = $new_channel;
|
||||
return( $clone );
|
||||
my $self = shift;
|
||||
my $new_channel = shift;
|
||||
my $clone = $self->clone();
|
||||
$clone->{channel} = $new_channel;
|
||||
return( $clone );
|
||||
}
|
||||
|
||||
sub accept()
|
||||
sub accept
|
||||
{
|
||||
my $self = shift;
|
||||
my $new_channel = $self->{channel}->accept();
|
||||
return( $self->_spawn( $new_channel ) );
|
||||
my $self = shift;
|
||||
my $new_channel = $self->{channel}->accept();
|
||||
return( $self->_spawn( $new_channel ) );
|
||||
}
|
||||
|
||||
sub open()
|
||||
sub open
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{channel}->open() );
|
||||
my $self = shift;
|
||||
return( $self->{channel}->open() );
|
||||
}
|
||||
|
||||
sub close()
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{channel}->close() );
|
||||
my $self = shift;
|
||||
return( $self->{channel}->close() );
|
||||
}
|
||||
|
||||
sub fileno()
|
||||
sub fileno
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{channel}->fileno() );
|
||||
my $self = shift;
|
||||
return( $self->{channel}->fileno() );
|
||||
}
|
||||
|
||||
sub isOpen()
|
||||
sub isOpen
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{channel}->isOpen() );
|
||||
my $self = shift;
|
||||
return( $self->{channel}->isOpen() );
|
||||
}
|
||||
|
||||
sub isConnected()
|
||||
sub isConnected
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{channel}->isConnected() );
|
||||
my $self = shift;
|
||||
return( $self->{channel}->isConnected() );
|
||||
}
|
||||
|
||||
sub canRead()
|
||||
sub canRead
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{input} && $self->isConnected() );
|
||||
my $self = shift;
|
||||
return( $self->{input} && $self->isConnected() );
|
||||
}
|
||||
|
||||
sub canWrite()
|
||||
sub canWrite
|
||||
{
|
||||
my $self = shift;
|
||||
return( $self->{output} && $self->isConnected() );
|
||||
my $self = shift;
|
||||
return( $self->{output} && $self->isConnected() );
|
||||
}
|
||||
|
||||
sub getMessages
|
||||
{
|
||||
my $self = shift;
|
||||
my $buffer = $self->{channel}->read();
|
||||
my $self = shift;
|
||||
my $buffer = $self->{channel}->read();
|
||||
|
||||
return( undef ) if ( !defined($buffer) );
|
||||
return( undef ) if ( !defined($buffer) );
|
||||
|
||||
my @messages = split( /\r?\n/, $buffer );
|
||||
return( \@messages );
|
||||
my @messages = split( /\r?\n/, $buffer );
|
||||
return( \@messages );
|
||||
}
|
||||
|
||||
sub putMessages
|
||||
{
|
||||
my $self = shift;
|
||||
my $messages = shift;
|
||||
my $self = shift;
|
||||
my $messages = shift;
|
||||
|
||||
if ( @$messages )
|
||||
{
|
||||
my $buffer = join( "\n", @$messages );
|
||||
$buffer .= "\n";
|
||||
if ( !$self->{channel}->write( $buffer ) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" );
|
||||
}
|
||||
}
|
||||
return( undef );
|
||||
if ( @$messages )
|
||||
{
|
||||
my $buffer = join( "\n", @$messages );
|
||||
$buffer .= "\n";
|
||||
if ( !$self->{channel}->write( $buffer ) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer
|
||||
." to connection "
|
||||
.$self->{name}
|
||||
." ("
|
||||
.$self->fileno()
|
||||
.")\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
return( undef );
|
||||
}
|
||||
|
||||
sub timedActions
|
||||
|
@ -167,22 +173,22 @@ sub DESTROY
|
|||
|
||||
sub AUTOLOAD
|
||||
{
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
elsif ( defined($self->{channel}) )
|
||||
{
|
||||
if ( exists($self->{channel}->{$name}) )
|
||||
{
|
||||
return( $self->{channel}->{$name} );
|
||||
}
|
||||
}
|
||||
croak( "Can't access $name member of object of class $class" );
|
||||
my $self = shift;
|
||||
my $class = ref($self) || croak( "$self not object" );
|
||||
my $name = $AUTOLOAD;
|
||||
$name =~ s/.*://;
|
||||
if ( exists($self->{$name}) )
|
||||
{
|
||||
return( $self->{$name} );
|
||||
}
|
||||
elsif ( defined($self->{channel}) )
|
||||
{
|
||||
if ( exists($self->{channel}->{$name}) )
|
||||
{
|
||||
return( $self->{channel}->{$name} );
|
||||
}
|
||||
}
|
||||
croak( "Can't access $name member of object of class $class" );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -44,40 +44,40 @@ use ZoneMinder::Logger qw(:all);
|
|||
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my $path = shift;
|
||||
my $self = ZoneMinder::Trigger::Connection->new( @_ );
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
my $class = shift;
|
||||
my $path = shift;
|
||||
my $self = ZoneMinder::Trigger::Connection->new( @_ );
|
||||
bless( $self, $class );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub getMessages
|
||||
{
|
||||
my $self = shift;
|
||||
my $buffer = $self->{channel}->read();
|
||||
my $self = shift;
|
||||
my $buffer = $self->{channel}->read();
|
||||
|
||||
return( undef ) if ( !defined($buffer) );
|
||||
return( undef ) if ( !defined($buffer) );
|
||||
|
||||
Debug( "Handling buffer '$buffer'\n" );
|
||||
my @messages = grep { s/-/|/g; 1; } split( /\r?\n/, $buffer );
|
||||
return( \@messages );
|
||||
Debug( "Handling buffer '$buffer'\n" );
|
||||
my @messages = grep { s/-/|/g; 1; } split( /\r?\n/, $buffer );
|
||||
return( \@messages );
|
||||
}
|
||||
|
||||
sub putMessages
|
||||
{
|
||||
my $self = shift;
|
||||
my $messages = shift;
|
||||
my $self = shift;
|
||||
my $messages = shift;
|
||||
|
||||
if ( @$messages )
|
||||
{
|
||||
my $buffer = join( "\n", grep{ s/\|/-/; 1; } @$messages );
|
||||
$buffer .= "\n";
|
||||
if ( !$self->{channel}->write( $buffer ) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" );
|
||||
}
|
||||
}
|
||||
return( undef );
|
||||
if ( @$messages )
|
||||
{
|
||||
my $buffer = join( "\n", grep{ s/\|/-/; 1; } @$messages );
|
||||
$buffer .= "\n";
|
||||
if ( !$self->{channel}->write( $buffer ) )
|
||||
{
|
||||
Error( "Unable to write buffer '".$buffer." to connection ".$self->{name}." (".$self->fileno().")\n" );
|
||||
}
|
||||
}
|
||||
return( undef );
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
148
scripts/zm.in
148
scripts/zm.in
|
@ -16,12 +16,12 @@ LOCKFILE=/var/lock/subsys/zm
|
|||
|
||||
loadconf()
|
||||
{
|
||||
if [ -f $ZM_CONFIG ]; then
|
||||
. $ZM_CONFIG
|
||||
else
|
||||
echo "ERROR: $ZM_CONFIG not found."
|
||||
return 1
|
||||
fi
|
||||
if [ -f $ZM_CONFIG ]; then
|
||||
. $ZM_CONFIG
|
||||
else
|
||||
echo "ERROR: $ZM_CONFIG not found."
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
loadconf
|
||||
|
@ -30,95 +30,95 @@ command="$ZM_PATH_BIN/zmpkg.pl"
|
|||
start()
|
||||
{
|
||||
# Commenting out as it is not needed. Leaving as a placeholder for future use.
|
||||
# zmupdate || return $?
|
||||
loadconf || return $?
|
||||
#Make sure the directory for our PID folder exists or create one.
|
||||
[ ! -d $pidfile ] \
|
||||
&& mkdir -m 774 $pidfile \
|
||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile
|
||||
#Make sure the folder for the socks file exists or create one
|
||||
GetPath="select Value from Config where Name='ZM_PATH_SOCKS'"
|
||||
# zmupdate || return $?
|
||||
loadconf || return $?
|
||||
#Make sure the directory for our PID folder exists or create one.
|
||||
[ ! -d $pidfile ] \
|
||||
&& mkdir -m 774 $pidfile \
|
||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile
|
||||
#Make sure the folder for the socks file exists or create one
|
||||
GetPath="select Value from Config where Name='ZM_PATH_SOCKS'"
|
||||
dbHost=`echo $ZM_DB_HOST | cut -d: -f1`
|
||||
dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2`
|
||||
if [ "$dbPort" = "" ]
|
||||
then
|
||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
||||
else
|
||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
||||
fi
|
||||
[ ! -d $ZM_PATH_SOCK ] \
|
||||
&& mkdir -m 774 $ZM_PATH_SOCK \
|
||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK
|
||||
echo -n $"Starting $prog: "
|
||||
$command start
|
||||
RETVAL=$?
|
||||
[ $RETVAL = 0 ] && success || failure
|
||||
echo
|
||||
[ $RETVAL = 0 ] && touch $LOCKFILE
|
||||
return $RETVAL
|
||||
[ ! -d $ZM_PATH_SOCK ] \
|
||||
&& mkdir -m 774 $ZM_PATH_SOCK \
|
||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK
|
||||
echo -n $"Starting $prog: "
|
||||
$command start
|
||||
RETVAL=$?
|
||||
[ $RETVAL = 0 ] && success || failure
|
||||
echo
|
||||
[ $RETVAL = 0 ] && touch $LOCKFILE
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
loadconf
|
||||
echo -n $"Stopping $prog: "
|
||||
$command stop
|
||||
RETVAL=$?
|
||||
[ $RETVAL = 0 ] && success || failure
|
||||
echo
|
||||
[ $RETVAL = 0 ] && rm -f $LOCKFILE
|
||||
loadconf
|
||||
echo -n $"Stopping $prog: "
|
||||
$command stop
|
||||
RETVAL=$?
|
||||
[ $RETVAL = 0 ] && success || failure
|
||||
echo
|
||||
[ $RETVAL = 0 ] && rm -f $LOCKFILE
|
||||
}
|
||||
|
||||
zmstatus()
|
||||
{
|
||||
loadconf
|
||||
result=`$command status`
|
||||
if [ "$result" = "running" ]; then
|
||||
echo "ZoneMinder is running"
|
||||
$ZM_PATH_BIN/zmu -l
|
||||
RETVAL=0
|
||||
else
|
||||
echo "ZoneMinder is stopped"
|
||||
RETVAL=1
|
||||
fi
|
||||
loadconf
|
||||
result=`$command status`
|
||||
if [ "$result" = "running" ]; then
|
||||
echo "ZoneMinder is running"
|
||||
$ZM_PATH_BIN/zmu -l
|
||||
RETVAL=0
|
||||
else
|
||||
echo "ZoneMinder is stopped"
|
||||
RETVAL=1
|
||||
fi
|
||||
}
|
||||
|
||||
zmupdate()
|
||||
{
|
||||
if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then
|
||||
$ZM_PATH_BIN/zmupdate.pl -f
|
||||
fi
|
||||
if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then
|
||||
$ZM_PATH_BIN/zmupdate.pl -f
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
start
|
||||
;;
|
||||
'stop')
|
||||
stop
|
||||
;;
|
||||
'restart')
|
||||
stop
|
||||
start
|
||||
;;
|
||||
'condrestart')
|
||||
loadconf
|
||||
result=`$ZM_PATH_BIN/zmdc.pl check`
|
||||
if [ "$result" = "running" ]; then
|
||||
$ZM_PATH_BIN/zmdc.pl shutdown > /dev/null
|
||||
rm -f $LOCKFILE
|
||||
start
|
||||
fi
|
||||
;;
|
||||
'status')
|
||||
status httpd
|
||||
status mysqld
|
||||
zmstatus
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 { start | stop | restart | condrestart | status }"
|
||||
RETVAL=1
|
||||
;;
|
||||
'start')
|
||||
start
|
||||
;;
|
||||
'stop')
|
||||
stop
|
||||
;;
|
||||
'restart')
|
||||
stop
|
||||
start
|
||||
;;
|
||||
'condrestart')
|
||||
loadconf
|
||||
result=`$ZM_PATH_BIN/zmdc.pl check`
|
||||
if [ "$result" = "running" ]; then
|
||||
$ZM_PATH_BIN/zmdc.pl shutdown > /dev/null
|
||||
rm -f $LOCKFILE
|
||||
start
|
||||
fi
|
||||
;;
|
||||
'status')
|
||||
status httpd
|
||||
status mysqld
|
||||
zmstatus
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 { start | stop | restart | condrestart | status }"
|
||||
RETVAL=1
|
||||
;;
|
||||
esac
|
||||
exit $RETVAL
|
||||
|
|
|
@ -20,15 +20,33 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script checks for consistency between the event filesystem and
|
||||
# the database. If events are found in one and not the other they are
|
||||
# deleted (optionally). Additionally any monitor event directories that
|
||||
# do not correspond to a database monitor are similarly disposed of.
|
||||
# However monitors in the database that don't have a directory are left
|
||||
# alone as this is valid if they are newly created and have no events
|
||||
# yet.
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmaudit.pl - ZoneMinder event file system and database consistency checker
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmaudit.pl [-r,-report|-i,-interactive]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script checks for consistency between the event filesystem and
|
||||
the database. If events are found in one and not the other they are
|
||||
deleted (optionally). Additionally any monitor event directories that
|
||||
do not correspond to a database monitor are similarly disposed of.
|
||||
However monitors in the database that don't have a directory are left
|
||||
alone as this is valid if they are newly created and have no events
|
||||
yet.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
-r, --report - Just report don't actually do anything
|
||||
-i, --interactive - Ask before applying any changes
|
||||
-c, --continuous - Run continuously
|
||||
-v, --version - Print the installed version of ZoneMinder
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -38,7 +56,6 @@ use bytes;
|
|||
#
|
||||
# ==========================================================================
|
||||
|
||||
use constant MIN_AGE => 300; # Minimum age when we will delete anything
|
||||
use constant MAX_AGED_DIRS => 10; # Number of event dirs to check age on
|
||||
use constant RECOVER_TAG => "(r)"; # Tag to append to event name when recovered
|
||||
use constant RECOVER_TEXT => "Recovered."; # Text to append to event notes when recovered
|
||||
|
@ -56,9 +73,13 @@ use POSIX;
|
|||
use File::Find;
|
||||
use Time::HiRes qw/gettimeofday/;
|
||||
use Getopt::Long;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
|
||||
use constant IMAGE_PATH => $Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_IMAGES};
|
||||
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
||||
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
|
||||
? $Config{ZM_DIR_EVENTS}
|
||||
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS})
|
||||
;
|
||||
|
||||
$| = 1;
|
||||
|
||||
|
@ -71,39 +92,24 @@ my $interactive = 0;
|
|||
my $continuous = 0;
|
||||
my $version;
|
||||
|
||||
sub usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmaudit.pl [-r,-report|-i,-interactive]
|
||||
Parameters are :-
|
||||
-r, --report - Just report don't actually do anything
|
||||
-i, --interactive - Ask before applying any changes
|
||||
-c, --continuous - Run continuously
|
||||
-v, --version - Print the installed version of ZoneMinder
|
||||
");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
sub aud_print( $ );
|
||||
sub confirm( ;$$ );
|
||||
sub deleteSwapImage();
|
||||
|
||||
logInit();
|
||||
logSetSignal();
|
||||
|
||||
if ( !GetOptions( report=>\$report, interactive=>\$interactive, continuous=>\$continuous, version=>\$version ) )
|
||||
{
|
||||
usage();
|
||||
}
|
||||
GetOptions(
|
||||
'report' =>\$report,
|
||||
'interactive' =>\$interactive,
|
||||
'continuous' =>\$continuous,
|
||||
'version' =>\$version
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
if ( $version ) {
|
||||
print( ZoneMinder::Base::ZM_VERSION . "\n");
|
||||
exit(0);
|
||||
print( ZoneMinder::Base::ZM_VERSION . "\n");
|
||||
exit(0);
|
||||
}
|
||||
if ( ($report + $interactive + $continuous) > 1 )
|
||||
{
|
||||
print( STDERR "Error, only one option may be specified\n" );
|
||||
usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
|
@ -113,36 +119,46 @@ chdir( EVENT_PATH );
|
|||
my $max_image_age = 6/24; # 6 hours
|
||||
my $max_swap_age = 24/24; # 24 hours
|
||||
my $image_path = IMAGE_PATH;
|
||||
my $swap_image_path = $Config{ZM_PATH_SWAP};
|
||||
|
||||
my $loop = 1;
|
||||
my $cleaned = 0;
|
||||
MAIN: while( $loop ) {
|
||||
while ( ! ( $dbh and $dbh->ping() ) ) {
|
||||
$dbh = zmDbConnect();
|
||||
while ( ! ( $dbh and $dbh->ping() ) ) {
|
||||
$dbh = zmDbConnect();
|
||||
|
||||
last if $dbh;
|
||||
if ( $continuous ) {
|
||||
# if we are running continuously, then just skip to the next interval, otherwise we are a one off run, so wait a second and retry until someone kills us.
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} );
|
||||
} else {
|
||||
sleep 1;
|
||||
} # end if
|
||||
} # end while can't connect to the db
|
||||
last if $dbh;
|
||||
if ( $continuous ) {
|
||||
# if we are running continuously, then just skip to the next
|
||||
# interval, otherwise we are a one off run, so wait a second and
|
||||
# retry until someone kills us.
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} );
|
||||
} else {
|
||||
sleep 1;
|
||||
} # end if
|
||||
} # end while can't connect to the db
|
||||
|
||||
my $db_monitors;
|
||||
if ( ! exists $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
Fatal("ZM_AUDIT_MIN_AGE is not set in config.");
|
||||
}
|
||||
|
||||
my $db_monitors;
|
||||
my $monitorSelectSql = "select Id from Monitors order by Id";
|
||||
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql ) or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
|
||||
my $eventSelectSql = "select Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age from Events where MonitorId = ? order by Id";
|
||||
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() );
|
||||
my $monitorSelectSth = $dbh->prepare_cached( $monitorSelectSql )
|
||||
or Fatal( "Can't prepare '$monitorSelectSql': ".$dbh->errstr() );
|
||||
my $eventSelectSql = "SELECT Id, (unix_timestamp() - unix_timestamp(StartTime)) as Age
|
||||
FROM Events WHERE MonitorId = ? ORDER BY Id";
|
||||
my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql )
|
||||
or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() );
|
||||
|
||||
$cleaned = 0;
|
||||
my $res = $monitorSelectSth->execute() or Fatal( "Can't execute: ".$monitorSelectSth->errstr() );
|
||||
my $res = $monitorSelectSth->execute()
|
||||
or Fatal( "Can't execute: ".$monitorSelectSth->errstr() );
|
||||
while( my $monitor = $monitorSelectSth->fetchrow_hashref() )
|
||||
{
|
||||
Debug( "Found database monitor '$monitor->{Id}'" );
|
||||
my $db_events = $db_monitors->{$monitor->{Id}} = {};
|
||||
my $res = $eventSelectSth->execute( $monitor->{Id} ) or Fatal( "Can't execute: ".$eventSelectSth->errstr() );
|
||||
my $res = $eventSelectSth->execute( $monitor->{Id} )
|
||||
or Fatal( "Can't execute: ".$eventSelectSth->errstr() );
|
||||
while ( my $event = $eventSelectSth->fetchrow_hashref() )
|
||||
{
|
||||
$db_events->{$event->{Id}} = $event->{Age};
|
||||
|
@ -151,7 +167,7 @@ MAIN: while( $loop ) {
|
|||
}
|
||||
|
||||
my $fs_monitors;
|
||||
foreach my $monitor ( <[0-9]*> )
|
||||
foreach my $monitor ( glob("[0-9]*") )
|
||||
{
|
||||
Debug( "Found filesystem monitor '$monitor'" );
|
||||
my $fs_events = $fs_monitors->{$monitor} = {};
|
||||
|
@ -159,12 +175,13 @@ MAIN: while( $loop ) {
|
|||
|
||||
if ( $Config{ZM_USE_DEEP_STORAGE} )
|
||||
{
|
||||
foreach my $day_dir ( <$monitor_dir/*/*/*> )
|
||||
foreach my $day_dir ( glob("$monitor_dir/*/*/*") )
|
||||
{
|
||||
Debug( "Checking $day_dir" );
|
||||
( $day_dir ) = ( $day_dir =~ /^(.*)$/ ); # De-taint
|
||||
chdir( $day_dir );
|
||||
opendir( DIR, "." ) or Fatal( "Can't open directory '$day_dir': $!" );
|
||||
opendir( DIR, "." )
|
||||
or Fatal( "Can't open directory '$day_dir': $!" );
|
||||
my @event_links = sort { $b <=> $a } grep { -l $_ } readdir( DIR );
|
||||
closedir( DIR );
|
||||
my $count = 0;
|
||||
|
@ -231,7 +248,7 @@ MAIN: while( $loop ) {
|
|||
{
|
||||
while ( my ( $fs_event, $age ) = each(%$fs_events ) )
|
||||
{
|
||||
if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > MIN_AGE)) )
|
||||
if ( !defined($db_events->{$fs_event}) && ($age < 0 || ($age > $Config{ZM_AUDIT_MIN_AGE})) )
|
||||
{
|
||||
aud_print( "Filesystem event '$fs_monitor/$fs_event' does not exist in database" );
|
||||
if ( confirm() )
|
||||
|
@ -256,7 +273,7 @@ MAIN: while( $loop ) {
|
|||
}
|
||||
|
||||
my $monitor_links;
|
||||
foreach my $link ( <*> )
|
||||
foreach my $link ( glob("*") )
|
||||
{
|
||||
next if ( !-l $link );
|
||||
next if ( -e $link );
|
||||
|
@ -274,13 +291,17 @@ MAIN: while( $loop ) {
|
|||
|
||||
$cleaned = 0;
|
||||
my $deleteMonitorSql = "delete low_priority from Monitors where Id = ?";
|
||||
my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql ) or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() );
|
||||
my $deleteMonitorSth = $dbh->prepare_cached( $deleteMonitorSql )
|
||||
or Fatal( "Can't prepare '$deleteMonitorSql': ".$dbh->errstr() );
|
||||
my $deleteEventSql = "delete low_priority from Events where Id = ?";
|
||||
my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql ) or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() );
|
||||
my $deleteEventSth = $dbh->prepare_cached( $deleteEventSql )
|
||||
or Fatal( "Can't prepare '$deleteEventSql': ".$dbh->errstr() );
|
||||
my $deleteFramesSql = "delete low_priority from Frames where EventId = ?";
|
||||
my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql ) or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() );
|
||||
my $deleteFramesSth = $dbh->prepare_cached( $deleteFramesSql )
|
||||
or Fatal( "Can't prepare '$deleteFramesSql': ".$dbh->errstr() );
|
||||
my $deleteStatsSql = "delete low_priority from Stats where EventId = ?";
|
||||
my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql ) or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() );
|
||||
my $deleteStatsSth = $dbh->prepare_cached( $deleteStatsSql )
|
||||
or Fatal( "Can't prepare '$deleteStatsSql': ".$dbh->errstr() );
|
||||
while ( my ( $db_monitor, $db_events ) = each(%$db_monitors) )
|
||||
{
|
||||
if ( my $fs_events = $fs_monitors->{$db_monitor} )
|
||||
|
@ -289,27 +310,33 @@ MAIN: while( $loop ) {
|
|||
{
|
||||
while ( my ( $db_event, $age ) = each(%$db_events ) )
|
||||
{
|
||||
if ( !defined($fs_events->{$db_event}) && ($age > MIN_AGE) )
|
||||
{
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" );
|
||||
if ( confirm() )
|
||||
{
|
||||
my $res = $deleteEventSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$res = $deleteFramesSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$res = $deleteStatsSth->execute( $db_event ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
if ( !defined($fs_events->{$db_event}) ) {
|
||||
if ( $age > $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem" );
|
||||
if ( confirm() ) {
|
||||
my $res = $deleteEventSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$res = $deleteFramesSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$res = $deleteStatsSth->execute( $db_event )
|
||||
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
} else {
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist in filesystem but too young to delete." );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#aud_print( "Database monitor '$db_monitor' does not exist in filesystem" );
|
||||
aud_print( "Database monitor '$db_monitor' does not exist in filesystem" );
|
||||
#if ( confirm() )
|
||||
#{
|
||||
# We don't actually do this in case it's new
|
||||
#my $res = $deleteMonitorSth->execute( $db_monitor ) or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() );
|
||||
#my $res = $deleteMonitorSth->execute( $db_monitor )
|
||||
# or Fatal( "Can't execute: ".$deleteMonitorSth->errstr() );
|
||||
#$cleaned = 1;
|
||||
#}
|
||||
}
|
||||
|
@ -318,15 +345,20 @@ MAIN: while( $loop ) {
|
|||
|
||||
# Remove orphaned events (with no monitor)
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedEventsSql = "select Events.Id, Events.Name from Events left join Monitors on (Events.MonitorId = Monitors.Id) where isnull(Monitors.Id)";
|
||||
my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql ) or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedEventsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() );
|
||||
my $selectOrphanedEventsSql = "SELECT Events.Id, Events.Name
|
||||
FROM Events LEFT JOIN Monitors ON (Events.MonitorId = Monitors.Id)
|
||||
WHERE isnull(Monitors.Id)";
|
||||
my $selectOrphanedEventsSth = $dbh->prepare_cached( $selectOrphanedEventsSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedEventsSth->errstr() );
|
||||
while( my $event = $selectOrphanedEventsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found orphaned event with no monitor '$event->{Id}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$res = $deleteEventSth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
|
@ -334,15 +366,19 @@ MAIN: while( $loop ) {
|
|||
|
||||
# Remove empty events (with no frames)
|
||||
$cleaned = 0;
|
||||
my $selectEmptyEventsSql = "select * from Events as E left join Frames as F on (E.Id = F.EventId) where isnull(F.EventId) and now() - interval ".MIN_AGE." second > E.StartTime";
|
||||
my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectEmptyEventsSth->execute() or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() );
|
||||
my $selectEmptyEventsSql = "SELECT * FROM Events as E LEFT JOIN Frames as F ON (E.Id = F.EventId)
|
||||
WHERE isnull(F.EventId) AND now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second > E.StartTime";
|
||||
my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql )
|
||||
or Fatal( "Can't prepare '$selectEmptyEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectEmptyEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectEmptyEventsSth->errstr() );
|
||||
while( my $event = $selectEmptyEventsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found empty event with no frame records '$event->{Id}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteEventSth->execute( $event->{Id} ) or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$res = $deleteEventSth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute: ".$deleteEventSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
|
@ -350,15 +386,19 @@ MAIN: while( $loop ) {
|
|||
|
||||
# Remove orphaned frame records
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedFramesSql = "select distinct EventId from Frames where EventId not in (select Id from Events)";
|
||||
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql ) or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedFramesSth->execute() or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() );
|
||||
my $selectOrphanedFramesSql = "SELECT DISTINCT EventId FROM Frames
|
||||
WHERE EventId NOT IN (SELECT Id FROM Events)";
|
||||
my $selectOrphanedFramesSth = $dbh->prepare_cached( $selectOrphanedFramesSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedFramesSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedFramesSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedFramesSth->errstr() );
|
||||
while( my $frame = $selectOrphanedFramesSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found orphaned frame records for event '$frame->{EventId}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteFramesSth->execute( $frame->{EventId} ) or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$res = $deleteFramesSth->execute( $frame->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteFramesSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
|
@ -366,32 +406,84 @@ MAIN: while( $loop ) {
|
|||
|
||||
# Remove orphaned stats records
|
||||
$cleaned = 0;
|
||||
my $selectOrphanedStatsSql = "select distinct EventId from Stats where EventId not in (select Id from Events)";
|
||||
my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql ) or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedStatsSth->execute() or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() );
|
||||
my $selectOrphanedStatsSql = "SELECT DISTINCT EventId FROM Stats
|
||||
WHERE EventId NOT IN (SELECT Id FROM Events)";
|
||||
my $selectOrphanedStatsSth = $dbh->prepare_cached( $selectOrphanedStatsSql )
|
||||
or Fatal( "Can't prepare '$selectOrphanedStatsSql': ".$dbh->errstr() );
|
||||
$res = $selectOrphanedStatsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectOrphanedStatsSth->errstr() );
|
||||
while( my $stat = $selectOrphanedStatsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found orphaned statistic records for event '$stat->{EventId}'" );
|
||||
if ( confirm() )
|
||||
{
|
||||
$res = $deleteStatsSth->execute( $stat->{EventId} ) or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$res = $deleteStatsSth->execute( $stat->{EventId} )
|
||||
or Fatal( "Can't execute: ".$deleteStatsSth->errstr() );
|
||||
$cleaned = 1;
|
||||
}
|
||||
}
|
||||
redo MAIN if ( $cleaned );
|
||||
|
||||
# New audit to close any events that were left open for longer than MIN_AGE seconds
|
||||
my $selectUnclosedEventsSql = "select E.Id, max(F.TimeStamp) as EndTime, unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, max(F.FrameId) as Frames, count(if(F.Score>0,1,NULL)) as AlarmFrames, sum(F.Score) as TotScore, max(F.Score) as MaxScore, M.EventPrefix as Prefix from Events as E left join Monitors as M on E.MonitorId = M.Id inner join Frames as F on E.Id = F.EventId where isnull(E.Frames) or isnull(E.EndTime) group by E.Id having EndTime < (now() - interval ".MIN_AGE." second)";
|
||||
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql ) or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
|
||||
my $updateUnclosedEventsSql = "update low_priority Events set Name = ?, EndTime = ?, Length = ?, Frames = ?, AlarmFrames = ?, TotScore = ?, AvgScore = ?, MaxScore = ?, Notes = concat_ws( ' ', Notes, ? ) where Id = ?";
|
||||
my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql ) or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectUnclosedEventsSth->execute() or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() );
|
||||
my $selectUnclosedEventsSql =
|
||||
"SELECT E.Id,
|
||||
max(F.TimeStamp) as EndTime,
|
||||
unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length,
|
||||
max(F.FrameId) as Frames,
|
||||
count(if(F.Score>0,1,NULL)) as AlarmFrames,
|
||||
sum(F.Score) as TotScore,
|
||||
max(F.Score) as MaxScore,
|
||||
M.EventPrefix as Prefix
|
||||
FROM Events as E
|
||||
LEFT JOIN Monitors as M on E.MonitorId = M.Id
|
||||
INNER JOIN Frames as F on E.Id = F.EventId
|
||||
WHERE isnull(E.Frames) or isnull(E.EndTime)
|
||||
GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}." second)"
|
||||
;
|
||||
my $selectUnclosedEventsSth = $dbh->prepare_cached( $selectUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$selectUnclosedEventsSql': ".$dbh->errstr() );
|
||||
my $updateUnclosedEventsSql =
|
||||
"UPDATE low_priority Events
|
||||
SET Name = ?,
|
||||
EndTime = ?,
|
||||
Length = ?,
|
||||
Frames = ?,
|
||||
AlarmFrames = ?,
|
||||
TotScore = ?,
|
||||
AvgScore = ?,
|
||||
MaxScore = ?,
|
||||
Notes = concat_ws( ' ', Notes, ? )
|
||||
WHERE Id = ?"
|
||||
;
|
||||
my $updateUnclosedEventsSth = $dbh->prepare_cached( $updateUnclosedEventsSql )
|
||||
or Fatal( "Can't prepare '$updateUnclosedEventsSql': ".$dbh->errstr() );
|
||||
$res = $selectUnclosedEventsSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectUnclosedEventsSth->errstr() );
|
||||
while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() )
|
||||
{
|
||||
aud_print( "Found open event '$event->{Id}'" );
|
||||
if ( confirm( 'close', 'closing' ) )
|
||||
{
|
||||
$res = $updateUnclosedEventsSth->execute( sprintf( "%s%d%s", $event->{Prefix}, $event->{Id}, RECOVER_TAG ), $event->{EndTime}, $event->{Length}, $event->{Frames}, $event->{AlarmFrames}, $event->{TotScore}, $event->{AlarmFrames}?int($event->{TotScore}/$event->{AlarmFrames}):0, $event->{MaxScore}, RECOVER_TEXT, $event->{Id} ) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() );
|
||||
$res = $updateUnclosedEventsSth->execute
|
||||
(
|
||||
sprintf("%s%d%s",
|
||||
$event->{Prefix},
|
||||
$event->{Id},
|
||||
RECOVER_TAG
|
||||
),
|
||||
$event->{EndTime},
|
||||
$event->{Length},
|
||||
$event->{Frames},
|
||||
$event->{AlarmFrames},
|
||||
$event->{TotScore},
|
||||
$event->{AlarmFrames}
|
||||
? int($event->{TotScore} / $event->{AlarmFrames})
|
||||
: 0
|
||||
,
|
||||
$event->{MaxScore},
|
||||
RECOVER_TEXT,
|
||||
$event->{Id}
|
||||
) or Fatal( "Can't execute: ".$updateUnclosedEventsSth->errstr() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,7 +497,7 @@ MAIN: while( $loop ) {
|
|||
}
|
||||
|
||||
# Now delete any old swap files
|
||||
( my $swap_image_root ) = ( $swap_image_path =~ /^(.*)$/ ); # De-taint
|
||||
( my $swap_image_root ) = ( $Config{ZM_PATH_SWAP} =~ /^(.*)$/ ); # De-taint
|
||||
File::Find::find( { wanted=>\&deleteSwapImage, untaint=>1 }, $swap_image_root );
|
||||
|
||||
# Prune the Logs table if required
|
||||
|
@ -414,26 +506,43 @@ MAIN: while( $loop ) {
|
|||
if ( $Config{ZM_LOG_DATABASE_LIMIT} =~ /^\d+$/ )
|
||||
{
|
||||
# Number of rows
|
||||
my $selectLogRowCountSql = "select count(*) as Rows from Logs";
|
||||
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql ) or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() );
|
||||
$res = $selectLogRowCountSth->execute() or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() );
|
||||
my $selectLogRowCountSql = "SELECT count(*) as Rows from Logs";
|
||||
my $selectLogRowCountSth = $dbh->prepare_cached( $selectLogRowCountSql )
|
||||
or Fatal( "Can't prepare '$selectLogRowCountSql': ".$dbh->errstr() );
|
||||
$res = $selectLogRowCountSth->execute()
|
||||
or Fatal( "Can't execute: ".$selectLogRowCountSth->errstr() );
|
||||
my $row = $selectLogRowCountSth->fetchrow_hashref();
|
||||
my $logRows = $row->{Rows};
|
||||
if ( $logRows > $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
{
|
||||
my $deleteLogByRowsSql = "delete low_priority from Logs order by TimeKey asc limit ?";
|
||||
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql ) or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} ) or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() );
|
||||
aud_print( "Deleted ".$deleteLogByRowsSth->rows()." log table entries by count\n" ) if ( $deleteLogByRowsSth->rows() );
|
||||
my $deleteLogByRowsSql = "DELETE low_priority FROM Logs ORDER BY TimeKey ASC LIMIT ?";
|
||||
my $deleteLogByRowsSth = $dbh->prepare_cached( $deleteLogByRowsSql )
|
||||
or Fatal( "Can't prepare '$deleteLogByRowsSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByRowsSth->execute( $logRows - $Config{ZM_LOG_DATABASE_LIMIT} )
|
||||
or Fatal( "Can't execute: ".$deleteLogByRowsSth->errstr() );
|
||||
if ( $deleteLogByRowsSth->rows() )
|
||||
{
|
||||
aud_print( "Deleted ".$deleteLogByRowsSth->rows()
|
||||
." log table entries by count\n" )
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Time of record
|
||||
my $deleteLogByTimeSql = "delete low_priority from Logs where TimeKey < unix_timestamp(now() - interval ".$Config{ZM_LOG_DATABASE_LIMIT}.")";
|
||||
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql ) or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByTimeSth->execute() or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() );
|
||||
aud_print( "Deleted ".$deleteLogByTimeSth->rows()." log table entries by time\n" ) if ( $deleteLogByTimeSth->rows() );
|
||||
my $deleteLogByTimeSql =
|
||||
"DELETE low_priority FROM Logs
|
||||
WHERE TimeKey < unix_timestamp(now() - interval ".$Config{ZM_LOG_DATABASE_LIMIT}.")";
|
||||
my $deleteLogByTimeSth = $dbh->prepare_cached( $deleteLogByTimeSql )
|
||||
or Fatal( "Can't prepare '$deleteLogByTimeSql': ".$dbh->errstr() );
|
||||
$res = $deleteLogByTimeSth->execute()
|
||||
or Fatal( "Can't execute: ".$deleteLogByTimeSth->errstr() );
|
||||
if ( $deleteLogByTimeSth->rows() ){
|
||||
aud_print( "Deleted ".$deleteLogByTimeSth->rows()
|
||||
." log table entries by time\n" )
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
$loop = $continuous;
|
||||
|
@ -443,7 +552,7 @@ MAIN: while( $loop ) {
|
|||
|
||||
exit( 0 );
|
||||
|
||||
sub aud_print( $ )
|
||||
sub aud_print
|
||||
{
|
||||
my $string = shift;
|
||||
if ( !$continuous )
|
||||
|
@ -456,7 +565,7 @@ sub aud_print( $ )
|
|||
}
|
||||
}
|
||||
|
||||
sub confirm( ;$$ )
|
||||
sub confirm
|
||||
{
|
||||
my $prompt = shift || "delete";
|
||||
my $action = shift || "deleting";
|
||||
|
@ -496,7 +605,7 @@ sub confirm( ;$$ )
|
|||
return( $yesno );
|
||||
}
|
||||
|
||||
sub deleteSwapImage()
|
||||
sub deleteSwapImage
|
||||
{
|
||||
my $file = $_;
|
||||
|
||||
|
|
|
@ -20,12 +20,43 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script provides a way to import new ptz camera controls & camera presets
|
||||
# into existing zoneminder systems. This script also provides a way to export
|
||||
# ptz camera controls & camera presets from an existing zoneminder system into
|
||||
# a sql file, which can then be easily imported to another zoneminder system.
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmcamtool.pl - ZoneMinder tool to import camera controls and presets
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmcamtool.pl [--user=<dbuser> --pass=<dbpass>]
|
||||
[--import [file.sql] [--overwrite]]
|
||||
[--export [name]]
|
||||
[--topreset id [--noregex]]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script provides a way to import new ptz camera controls & camera presets
|
||||
into existing zoneminder systems. This script also provides a way to export
|
||||
ptz camera controls & camera presets from an existing zoneminder system into
|
||||
a sql file, which can then be easily imported to another zoneminder system.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
--export - Export all camera controls and presets to STDOUT.
|
||||
Optionally specify a control or preset name.
|
||||
--import [file.sql] - Import new camera controls and presets found in
|
||||
zm_create.sql into the ZoneMinder dB.
|
||||
Optionally specify an alternate sql file to read from.
|
||||
--overwrite - Overwrite any existing controls or presets.
|
||||
with the same name as the new controls or presets.
|
||||
--topreset id - Copy a monitor to a Camera Preset given the monitor id.
|
||||
--noregex - Do not try to find and replace fields such as usernames,
|
||||
passwords, IP addresses, etc with generic placeholders
|
||||
when converting a monitor to a preset.
|
||||
--help - Print usage information.
|
||||
--user=<dbuser> - Alternate dB user with privileges to alter dB.
|
||||
--pass=<dbpass> - Password of alternate dB user with privileges to alter dB.
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -35,6 +66,7 @@ use ZoneMinder::Logger qw(:all);
|
|||
use ZoneMinder::Database qw(:all);
|
||||
use DBI;
|
||||
use Getopt::Long;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
|
||||
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
|
||||
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
|
||||
|
@ -57,256 +89,258 @@ my $dbUser = $Config{ZM_DB_USER};
|
|||
my $dbPass = $Config{ZM_DB_PASS};
|
||||
my $version = 0;
|
||||
|
||||
# Process commandline parameters with getopt long
|
||||
if ( !GetOptions( 'export'=>\$export, 'import'=>\$import, 'overwrite'=>\$overwrite, 'help'=>\$help, 'topreset'=>\$topreset, 'noregex'=>\$noregex, 'user:s'=>\$dbUser, 'pass:s'=>\$dbPass, 'version'=>\$version ) ) {
|
||||
Usage();
|
||||
}
|
||||
GetOptions(
|
||||
'export' =>\$export,
|
||||
'import' =>\$import,
|
||||
'overwrite' =>\$overwrite,
|
||||
'help' =>\$help,
|
||||
'topreset' =>\$topreset,
|
||||
'noregex' =>\$noregex,
|
||||
'user:s' =>\$dbUser,
|
||||
'pass:s' =>\$dbPass,
|
||||
'version' =>\$version
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
$Config{ZM_DB_USER} = $dbUser;
|
||||
$Config{ZM_DB_PASS} = $dbPass;
|
||||
|
||||
if ( $version ) {
|
||||
print( ZoneMinder::Base::ZM_VERSION . "\n");
|
||||
exit(0);
|
||||
print( ZoneMinder::Base::ZM_VERSION . "\n");
|
||||
exit(0);
|
||||
}
|
||||
# Check to make sure commandline params make sense
|
||||
if ( ((!$help) && ($import + $export + $topreset) != 1 )) {
|
||||
print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ );
|
||||
Usage();
|
||||
print( STDERR qq/Please give only one of the following: "import", "export", or "topreset".\n/ );
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ( ($export)&&($overwrite) ) {
|
||||
print( "Warning: Overwrite parameter ignored during an export.\n");
|
||||
print( "Warning: Overwrite parameter ignored during an export.\n");
|
||||
}
|
||||
|
||||
if ( ($noregex)&&(!$topreset) ) {
|
||||
print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/);
|
||||
print( qq/Warning: Noregex parameter only applies when "topreset" parameter is also set. Ignoring.\n/);
|
||||
}
|
||||
|
||||
if ( ($topreset)&&($ARGV[0] !~ /\d\d*/) ) {
|
||||
print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ );
|
||||
Usage();
|
||||
print( STDERR qq/Parameter "topreset" requires a valid monitor ID.\n/ );
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
# Call the appropriate subroutine based on the params given on the commandline
|
||||
if ($help) {
|
||||
Usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ($export) {
|
||||
exportsql();
|
||||
exportsql();
|
||||
}
|
||||
|
||||
if ($import) {
|
||||
importsql();
|
||||
importsql();
|
||||
}
|
||||
|
||||
if ($topreset) {
|
||||
toPreset();
|
||||
toPreset();
|
||||
}
|
||||
|
||||
###############
|
||||
# SUBROUTINES #
|
||||
###############
|
||||
|
||||
# Usage subroutine help text
|
||||
sub Usage
|
||||
{
|
||||
die("
|
||||
USAGE:
|
||||
zmcamtool.pl [--user=<dbuser> --pass=<dbpass>]
|
||||
[--import [file.sql] [--overwrite]]
|
||||
[--export [name]]
|
||||
[--topreset id [--noregex]]
|
||||
|
||||
PARAMETERS:
|
||||
--export - Export all camera controls and presets to STDOUT.
|
||||
Optionally specify a control or preset name.
|
||||
--import [file.sql] - Import new camera controls and presets found in
|
||||
zm_create.sql into the ZoneMinder dB.
|
||||
Optionally specify an alternate sql file to read from.
|
||||
--overwrite - Overwrite any existing controls or presets.
|
||||
with the same name as the new controls or presets.
|
||||
--topreset id - Copy a monitor to a Camera Preset given the monitor id.
|
||||
--noregex - Do not try to find and replace fields such as usernames,
|
||||
passwords, ip addresses, etc with generic placeholders
|
||||
when converting a monitor to a preset.
|
||||
--help - Print usage information.
|
||||
--user=<dbuser> - Alternate dB user with privileges to alter dB.
|
||||
--pass=<dbpass> - Password of alternate dB user with privileges to alter dB.
|
||||
\n");
|
||||
}
|
||||
|
||||
# Execute a pre-built sql select query
|
||||
sub selectQuery
|
||||
{
|
||||
my $dbh = shift;
|
||||
my $sql = shift;
|
||||
my $monitorid = shift;
|
||||
my $dbh = shift;
|
||||
my $sql = shift;
|
||||
my $monitorid = shift;
|
||||
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute($monitorid) or die( "Can't execute: ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute($monitorid)
|
||||
or die( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
my @data = $sth->fetchrow_array();
|
||||
$sth->finish();
|
||||
my @data = $sth->fetchrow_array();
|
||||
$sth->finish();
|
||||
|
||||
return @data;
|
||||
return @data;
|
||||
}
|
||||
|
||||
# Exectute a pre-built sql query
|
||||
sub runQuery
|
||||
{
|
||||
my $dbh = shift;
|
||||
my $sql = shift;
|
||||
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();
|
||||
my $dbh = shift;
|
||||
my $sql = shift;
|
||||
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();
|
||||
|
||||
return $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
# Build and execute a sql insert query
|
||||
sub insertQuery
|
||||
{
|
||||
my $dbh = shift;
|
||||
my $tablename = shift;
|
||||
my @data = @_;
|
||||
my $dbh = shift;
|
||||
my $tablename = shift;
|
||||
my @data = @_;
|
||||
|
||||
my $sql = "insert into $tablename values (NULL,".(join ", ", ("?") x @data).")"; # Add "?" for each array element
|
||||
my $sql = "INSERT INTO $tablename VALUES (NULL,"
|
||||
.(join ", ", ("?") x @data).")"; # Add "?" for each array element
|
||||
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute(@data) or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute(@data)
|
||||
or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
||||
return $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
# Build and execute a sql delete query
|
||||
sub deleteQuery
|
||||
{
|
||||
my $dbh = shift;
|
||||
my $sqltable = shift;
|
||||
my $sqlname = shift;
|
||||
my $dbh = shift;
|
||||
my $sqltable = shift;
|
||||
my $sqlname = shift;
|
||||
|
||||
my $sql = "delete from $sqltable where Name = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
my $sql = "DELETE FROM $sqltable WHERE Name = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute($sqlname)
|
||||
or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
|
||||
return $res;
|
||||
return $res;
|
||||
}
|
||||
|
||||
# Build and execute a sql select count query
|
||||
sub checkExists
|
||||
{
|
||||
my $dbh = shift;
|
||||
my $sqltable = shift;
|
||||
my $sqlname = shift;
|
||||
my $result = 0;
|
||||
my $dbh = shift;
|
||||
my $sqltable = shift;
|
||||
my $sqlname = shift;
|
||||
my $result = 0;
|
||||
|
||||
my $sql = "select count(*) from $sqltable where Name = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute($sqlname) or die( "Can't execute: ".$sth->errstr() );
|
||||
my $sql = "SELECT count(*) FROM $sqltable WHERE Name = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute($sqlname)
|
||||
or die( "Can't execute: ".$sth->errstr() );
|
||||
|
||||
my $rows = $sth->fetchrow_arrayref();
|
||||
$sth->finish();
|
||||
my $rows = $sth->fetchrow_arrayref();
|
||||
$sth->finish();
|
||||
|
||||
if ($rows->[0] > 0) {
|
||||
$result = 1;
|
||||
}
|
||||
if ($rows->[0] > 0) {
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
# Import camera control & presets into the zoneminder dB
|
||||
sub importsql
|
||||
{
|
||||
my @newcontrols;
|
||||
my @overwritecontrols;
|
||||
my @skippedcontrols;
|
||||
my @newpresets;
|
||||
my @overwritepresets;
|
||||
my @skippedpresets;
|
||||
my %controls;
|
||||
my %monitorpresets;
|
||||
my @newcontrols;
|
||||
my @overwritecontrols;
|
||||
my @skippedcontrols;
|
||||
my @newpresets;
|
||||
my @overwritepresets;
|
||||
my @skippedpresets;
|
||||
my %controls;
|
||||
my %monitorpresets;
|
||||
|
||||
if ($ARGV[0]) {
|
||||
$sqlfile = $ARGV[0];
|
||||
} else {
|
||||
$sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql';
|
||||
}
|
||||
if ($ARGV[0]) {
|
||||
$sqlfile = $ARGV[0];
|
||||
} else {
|
||||
$sqlfile = $Config{ZM_PATH_DATA}.'/db/zm_create.sql';
|
||||
}
|
||||
|
||||
open(my $SQLFILE,"<",$sqlfile) or die( "Can't Open file: $!\n" );
|
||||
open(my $SQLFILE,"<",$sqlfile)
|
||||
or die( "Can't Open file: $!\n" );
|
||||
|
||||
# Find and extract ptz control and monitor preset records
|
||||
while (<$SQLFILE>) {
|
||||
# Our regex replaces the primary key with NULL
|
||||
if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) {
|
||||
$controls{$3} = $_;
|
||||
} elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) {
|
||||
$monitorpresets{$3} = $_;
|
||||
}
|
||||
}
|
||||
close $SQLFILE;
|
||||
# Find and extract ptz control and monitor preset records
|
||||
while (<$SQLFILE>) {
|
||||
# Our regex replaces the primary key with NULL
|
||||
if (s/^(INSERT INTO .*?Controls.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) {
|
||||
$controls{$3} = $_;
|
||||
} elsif (s/^(INSERT INTO .*?MonitorPresets.*? VALUES \().*?(,')(.*?)(',.*)/$1NULL$2$3$4/i) {
|
||||
$monitorpresets{$3} = $_;
|
||||
}
|
||||
}
|
||||
close $SQLFILE;
|
||||
|
||||
if ( ! (%controls || %monitorpresets) ) {
|
||||
die( "Error: No relevant data found in $sqlfile.\n" );
|
||||
}
|
||||
if ( ! (%controls || %monitorpresets) ) {
|
||||
die( "Error: No relevant data found in $sqlfile.\n" );
|
||||
}
|
||||
|
||||
# Now that we've got what we were looking for, compare to what is already in the dB
|
||||
# Now that we've got what we were looking for,
|
||||
# compare to what is already in the dB
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
foreach (keys %controls) {
|
||||
if (!checkExists($dbh,"Controls",$_)) {
|
||||
# No existing Control was found. Add new control to dB.
|
||||
runQuery($dbh,$controls{$_});
|
||||
push @newcontrols, $_;
|
||||
} elsif ($overwrite) {
|
||||
# An existing Control was found and the overwrite flag is set. Overwrite the control.
|
||||
deleteQuery($dbh,"Controls",$_);
|
||||
runQuery($dbh,$controls{$_});
|
||||
push @overwritecontrols, $_;
|
||||
} else {
|
||||
# An existing Control was found and the overwrite flag was not set. Do nothing.
|
||||
push @skippedcontrols, $_;
|
||||
}
|
||||
}
|
||||
my $dbh = zmDbConnect();
|
||||
foreach (keys %controls) {
|
||||
if (!checkExists($dbh,"Controls",$_)) {
|
||||
# No existing Control was found. Add new control to dB.
|
||||
runQuery($dbh,$controls{$_});
|
||||
push @newcontrols, $_;
|
||||
} elsif ($overwrite) {
|
||||
# An existing Control was found and the overwrite flag is set.
|
||||
# Overwrite the control.
|
||||
deleteQuery($dbh,"Controls",$_);
|
||||
runQuery($dbh,$controls{$_});
|
||||
push @overwritecontrols, $_;
|
||||
} else {
|
||||
# An existing Control was found and the overwrite flag was not set.
|
||||
# Do nothing.
|
||||
push @skippedcontrols, $_;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (keys %monitorpresets) {
|
||||
if (!checkExists($dbh,"MonitorPresets",$_)) {
|
||||
# No existing MonitorPreset was found. Add new MonitorPreset to dB.
|
||||
runQuery($dbh,$monitorpresets{$_});
|
||||
push @newpresets, $_;
|
||||
} elsif ($overwrite) {
|
||||
# An existing MonitorPreset was found and the overwrite flag is set. Overwrite the MonitorPreset.
|
||||
deleteQuery($dbh,"MonitorPresets",$_);
|
||||
runQuery($dbh,$monitorpresets{$_});
|
||||
push @overwritepresets, $_;
|
||||
} else {
|
||||
# An existing MonitorPreset was found and the overwrite flag was not set. Do nothing.
|
||||
push @skippedpresets, $_;
|
||||
}
|
||||
}
|
||||
foreach (keys %monitorpresets) {
|
||||
if (!checkExists($dbh,"MonitorPresets",$_)) {
|
||||
# No existing MonitorPreset was found. Add new MonitorPreset to dB.
|
||||
runQuery($dbh,$monitorpresets{$_});
|
||||
push @newpresets, $_;
|
||||
} elsif ($overwrite) {
|
||||
# An existing MonitorPreset was found and the overwrite flag is set.
|
||||
# Overwrite the MonitorPreset.
|
||||
deleteQuery($dbh,"MonitorPresets",$_);
|
||||
runQuery($dbh,$monitorpresets{$_});
|
||||
push @overwritepresets, $_;
|
||||
} else {
|
||||
# An existing MonitorPreset was found and the overwrite flag was
|
||||
# not set. Do nothing.
|
||||
push @skippedpresets, $_;
|
||||
}
|
||||
}
|
||||
|
||||
if (@newcontrols) {
|
||||
print "Number of ptz camera controls added: ".scalar(@newcontrols)."\n";
|
||||
}
|
||||
if (@overwritecontrols) {
|
||||
print "Number of existing ptz camera controls overwritten: ".scalar(@overwritecontrols)."\n";
|
||||
}
|
||||
if (@skippedcontrols) {
|
||||
print "Number of existing ptz camera controls skipped: ".scalar(@skippedcontrols)."\n";
|
||||
}
|
||||
if (@newcontrols) {
|
||||
print "Number of ptz camera controls added: "
|
||||
.scalar(@newcontrols)."\n";
|
||||
}
|
||||
if (@overwritecontrols) {
|
||||
print "Number of existing ptz camera controls overwritten: "
|
||||
.scalar(@overwritecontrols)."\n";
|
||||
}
|
||||
if (@skippedcontrols) {
|
||||
print "Number of existing ptz camera controls skipped: "
|
||||
.scalar(@skippedcontrols)."\n";
|
||||
}
|
||||
|
||||
if (@newpresets) {
|
||||
print "Number of monitor presets added: ".scalar(@newpresets)."\n";
|
||||
}
|
||||
if (@overwritepresets) {
|
||||
print "Number of existing monitor presets overwritten: ".scalar(@overwritepresets)."\n";
|
||||
}
|
||||
if (@skippedpresets) {
|
||||
print "Number of existing presets skipped: ".scalar(@skippedpresets)."\n";
|
||||
}
|
||||
if (@newpresets) {
|
||||
print "Number of monitor presets added: "
|
||||
.scalar(@newpresets)."\n";
|
||||
}
|
||||
if (@overwritepresets) {
|
||||
print "Number of existing monitor presets overwritten: "
|
||||
.scalar(@overwritepresets)."\n";
|
||||
}
|
||||
if (@skippedpresets) {
|
||||
print "Number of existing presets skipped: "
|
||||
.scalar(@skippedpresets)."\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Export camera controls & presets from the zoneminder dB to STDOUT
|
||||
|
@ -317,14 +351,14 @@ my ( $host, $port ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
|||
my $command = "mysqldump -t --skip-opt --compact -h".$host;
|
||||
$command .= " -P".$port if defined($port);
|
||||
if ( $dbUser ) {
|
||||
$command .= " -u".$dbUser;
|
||||
if ( $dbPass ) {
|
||||
$command .= " -p".$dbPass;
|
||||
}
|
||||
}
|
||||
$command .= " -u".$dbUser;
|
||||
if ( $dbPass ) {
|
||||
$command .= " -p".$dbPass;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ARGV[0]) {
|
||||
$command .= qq( --where="Name = '$ARGV[0]'");
|
||||
$command .= qq( --where="Name = '$ARGV[0]'");
|
||||
}
|
||||
|
||||
$command .= " zm Controls MonitorPresets";
|
||||
|
@ -332,78 +366,81 @@ $command .= " zm Controls MonitorPresets";
|
|||
my $output = qx($command);
|
||||
my $status = $? >> 8;
|
||||
if ( $status || logDebugging() ) {
|
||||
chomp( $output );
|
||||
print( "Output: $output\n" );
|
||||
chomp( $output );
|
||||
print( "Output: $output\n" );
|
||||
}
|
||||
if ( $status ) {
|
||||
die( "Command '$command' exited with status: $status\n" );
|
||||
die( "Command '$command' exited with status: $status\n" );
|
||||
} else {
|
||||
# NULLify the primary keys before printing the output to STDOUT
|
||||
$output =~ s/VALUES \((.*?),'/VALUES \(NULL,'/ig;
|
||||
print $output;
|
||||
}
|
||||
# NULLify the primary keys before printing the output to STDOUT
|
||||
$output =~ s/VALUES \((.*?),'/VALUES \(NULL,'/ig;
|
||||
print $output;
|
||||
}
|
||||
}
|
||||
|
||||
sub toPreset
|
||||
{
|
||||
my $dbh = zmDbConnect();
|
||||
my $monitorid = $ARGV[0];
|
||||
my $dbh = zmDbConnect();
|
||||
my $monitorid = $ARGV[0];
|
||||
|
||||
# Grap the following fields from the Monitors table
|
||||
my $sql = "select
|
||||
Name,
|
||||
Type,
|
||||
Device,
|
||||
Channel,
|
||||
Format,
|
||||
Protocol,
|
||||
Method,
|
||||
Host,
|
||||
Port,
|
||||
Path,
|
||||
SubPath,
|
||||
Width,
|
||||
Height,
|
||||
Palette,
|
||||
MaxFPS,
|
||||
Controllable,
|
||||
ControlId,
|
||||
ControlDevice,
|
||||
ControlAddress,
|
||||
DefaultRate,
|
||||
DefaultScale
|
||||
from Monitors where Id = ?";
|
||||
my @data = selectQuery($dbh,$sql,$monitorid);
|
||||
# Grap the following fields from the Monitors table
|
||||
my $sql = "SELECT
|
||||
Name,
|
||||
Type,
|
||||
Device,
|
||||
Channel,
|
||||
Format,
|
||||
Protocol,
|
||||
Method,
|
||||
Host,
|
||||
Port,
|
||||
Path,
|
||||
SubPath,
|
||||
Width,
|
||||
Height,
|
||||
Palette,
|
||||
MaxFPS,
|
||||
Controllable,
|
||||
ControlId,
|
||||
ControlDevice,
|
||||
ControlAddress,
|
||||
DefaultRate,
|
||||
DefaultScale
|
||||
FROM Monitors WHERE Id = ?";
|
||||
my @data = selectQuery($dbh,$sql,$monitorid);
|
||||
|
||||
if (!@data) {
|
||||
die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" );
|
||||
}
|
||||
if (!@data) {
|
||||
die( "Error: Monitor Id $monitorid does not appear to exist in the database.\n" );
|
||||
}
|
||||
|
||||
# Attempt to search for and replace system specific values such as ip addresses, ports, usernames, etc. with generic placeholders
|
||||
if (!$noregex) {
|
||||
foreach (@data) {
|
||||
s/\b(?:\d{1,3}\.){3}\d{1,3}\b/<ip-address>/; # ip address
|
||||
s/<ip-address>:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/<ip-address>:<port>/; # tcpip port
|
||||
s/\/\/.*:.*@/\/\/<username>:<pwd>@/; # user & pwd preceeding an ip address
|
||||
s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=<username>$3/i; # username embeded in url
|
||||
s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=<pwd>$3/i; # password embeded in url
|
||||
s/\w\w*:\w\w*/<username>:<pwd>/; # user & pwd in their own field
|
||||
s/\/dev\/video\d\d*/\/dev\/video<?>/; # local video devices
|
||||
}
|
||||
}
|
||||
# Attempt to search for and replace system specific values such as
|
||||
# ip addresses, ports, usernames, etc. with generic placeholders
|
||||
if (!$noregex) {
|
||||
foreach (@data) {
|
||||
s/\b(?:\d{1,3}\.){3}\d{1,3}\b/<ip-address>/; # ip address
|
||||
s/<ip-address>:(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$/<ip-address>:<port>/; # tcpip port
|
||||
s/\/\/.*:.*@/\/\/<username>:<pwd>@/; # user & pwd preceeding an ip address
|
||||
s/(&|\?)(user|username)=\w\w*(&|\?)/$1$2=<username>$3/i; # username embeded in url
|
||||
s/(&|\?)(pwd|password)=\w\w*(&|\?)/$1$2=<pwd>$3/i; # password embeded in url
|
||||
s/\w\w*:\w\w*/<username>:<pwd>/; # user & pwd in their own field
|
||||
s/\/dev\/video\d\d*/\/dev\/video<?>/; # local video devices
|
||||
}
|
||||
}
|
||||
|
||||
if (!checkExists($dbh,"MonitorPresets",$data[0])) {
|
||||
# No existing Preset was found. Add new Preset to dB.
|
||||
print "Adding new preset: $data[0]\n";
|
||||
insertQuery($dbh,"MonitorPresets",@data);
|
||||
} elsif ($overwrite) {
|
||||
# An existing Control was found and the overwrite flag is set. Overwrite the control.
|
||||
print "Existing preset $data[0] detected.\nOverwriting...\n";
|
||||
deleteQuery($dbh,"MonitorPresets",$data[0]);
|
||||
insertQuery($dbh,"MonitorPresets",@data);
|
||||
} else {
|
||||
# An existing Control was found and the overwrite flag was not set. Do nothing.
|
||||
print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n";
|
||||
}
|
||||
if (!checkExists($dbh,"MonitorPresets",$data[0])) {
|
||||
# No existing Preset was found. Add new Preset to dB.
|
||||
print "Adding new preset: $data[0]\n";
|
||||
insertQuery($dbh,"MonitorPresets",@data);
|
||||
} elsif ($overwrite) {
|
||||
# An existing Control was found and the overwrite flag is set.
|
||||
# Overwrite the control.
|
||||
print "Existing preset $data[0] detected.\nOverwriting...\n";
|
||||
deleteQuery($dbh,"MonitorPresets",$data[0]);
|
||||
insertQuery($dbh,"MonitorPresets",@data);
|
||||
} else {
|
||||
# An existing Control was found and the overwrite flag was not set.
|
||||
# Do nothing.
|
||||
print "Existing preset $data[0] detected and overwrite flag not set.\nSkipping...\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,16 +20,39 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script continuously monitors the recorded events for the given
|
||||
# monitor and applies any filters which would delete and/or upload
|
||||
# matching events
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmcontrol.pl - ZoneMinder control script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmcontrol.pl --id {monitor_id} --command={command} [various options]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
FIXME FIXME
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
--autostop -
|
||||
--xcoord [ arg ] - X-coord
|
||||
--ycoord [ arg ] - Y-coord
|
||||
--speed [ arg ] - Speed
|
||||
--step [ arg ] -
|
||||
--panspeed [ arg ] -
|
||||
--panstep [ arg ] -
|
||||
--tiltspeed [ arg ] -
|
||||
--tiltstep [ arg ] -
|
||||
--preset [ arg ] -
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
|
||||
@EXTRA_PERL_LIB@
|
||||
use ZoneMinder;
|
||||
use Getopt::Long;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
use POSIX qw/strftime EPIPE/;
|
||||
use Socket;
|
||||
#use Data::Dumper;
|
||||
|
@ -44,14 +67,6 @@ $ENV{PATH} = '/bin:/usr/bin';
|
|||
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
|
||||
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||
|
||||
sub Usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmcontrol.pl --id <monitor_id> --command=<command> <various options>
|
||||
");
|
||||
exit();
|
||||
}
|
||||
|
||||
logInit();
|
||||
|
||||
my $arg_string = join( " ", @ARGV );
|
||||
|
@ -59,29 +74,25 @@ my $arg_string = join( " ", @ARGV );
|
|||
my $id;
|
||||
my %options;
|
||||
|
||||
if ( !GetOptions(
|
||||
'id=i'=>\$id,
|
||||
'command=s'=>\$options{command},
|
||||
'xcoord=i'=>\$options{xcoord},
|
||||
'ycoord=i'=>\$options{ycoord},
|
||||
'speed=i'=>\$options{speed},
|
||||
'step=i'=>\$options{step},
|
||||
'panspeed=i'=>\$options{panspeed},
|
||||
'tiltspeed=i'=>\$options{tiltspeed},
|
||||
'panstep=i'=>\$options{panstep},
|
||||
'tiltstep=i'=>\$options{tiltstep},
|
||||
'preset=i'=>\$options{preset},
|
||||
'autostop'=>\$options{autostop},
|
||||
)
|
||||
)
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
GetOptions(
|
||||
'id=i' =>\$id,
|
||||
'command=s' =>\$options{command},
|
||||
'xcoord=i' =>\$options{xcoord},
|
||||
'ycoord=i' =>\$options{ycoord},
|
||||
'speed=i' =>\$options{speed},
|
||||
'step=i' =>\$options{step},
|
||||
'panspeed=i' =>\$options{panspeed},
|
||||
'tiltspeed=i' =>\$options{tiltspeed},
|
||||
'panstep=i' =>\$options{panstep},
|
||||
'tiltstep=i' =>\$options{tiltstep},
|
||||
'preset=i' =>\$options{preset},
|
||||
'autostop' =>\$options{autostop},
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
if ( !$id || !$options{command} )
|
||||
{
|
||||
print( STDERR "Please give a valid monitor id and command\n" );
|
||||
Usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
( $id ) = $id =~ /^(\w+)$/;
|
||||
|
@ -90,13 +101,14 @@ Debug( $arg_string );
|
|||
|
||||
my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock';
|
||||
|
||||
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
|
||||
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 )
|
||||
or Fatal( "Can't open socket: $!" );
|
||||
|
||||
my $saddr = sockaddr_un( $sock_file );
|
||||
my $server_up = connect( CLIENT, $saddr );
|
||||
if ( !$server_up )
|
||||
{
|
||||
# The server isn't there
|
||||
# The server isn't there
|
||||
my $monitor = zmDbGetMonitorAndControl( $id );
|
||||
if ( !$monitor )
|
||||
{
|
||||
|
@ -129,16 +141,17 @@ if ( !$server_up )
|
|||
Info( "Starting control server $id/$protocol" );
|
||||
close( CLIENT );
|
||||
|
||||
if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) {
|
||||
Fatal("Can't load ZoneMinder::Control::$protocol");
|
||||
}
|
||||
if ( ! can_load( modules => { "ZoneMinder::Control::$protocol" => undef } ) ) {
|
||||
Fatal("Can't load ZoneMinder::Control::$protocol");
|
||||
}
|
||||
|
||||
if ( my $cpid = fork() )
|
||||
{
|
||||
logReinit();
|
||||
|
||||
# Parent process just sleep and fall through
|
||||
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" );
|
||||
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 )
|
||||
or die( "Can't open socket: $!" );
|
||||
my $attempts = 0;
|
||||
while (!connect( CLIENT, $saddr ))
|
||||
{
|
||||
|
@ -156,7 +169,9 @@ if ( !$server_up )
|
|||
|
||||
logReinit();
|
||||
|
||||
Info( "Control server $id/$protocol starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) );
|
||||
Info( "Control server $id/$protocol starting at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
);
|
||||
|
||||
$0 = $0." --id $id";
|
||||
|
||||
|
@ -166,7 +181,8 @@ if ( !$server_up )
|
|||
|
||||
$control->open();
|
||||
|
||||
socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
|
||||
socket( SERVER, PF_UNIX, SOCK_STREAM, 0 )
|
||||
or Fatal( "Can't open socket: $!" );
|
||||
unlink( $sock_file );
|
||||
bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" );
|
||||
listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" );
|
||||
|
@ -193,9 +209,9 @@ if ( !$server_up )
|
|||
|
||||
my $command = $params->{command};
|
||||
close( CLIENT );
|
||||
if ( $command eq 'quit' ) {
|
||||
last;
|
||||
}
|
||||
if ( $command eq 'quit' ) {
|
||||
last;
|
||||
}
|
||||
$control->$command( $params );
|
||||
}
|
||||
else
|
||||
|
@ -220,7 +236,9 @@ if ( !$server_up )
|
|||
last;
|
||||
}
|
||||
}
|
||||
Info( "Control server $id/$protocol exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() ) );
|
||||
Info( "Control server $id/$protocol exiting at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
);
|
||||
unlink( $sock_file );
|
||||
$control->close();
|
||||
exit( 0 );
|
||||
|
|
|
@ -20,13 +20,30 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script is the gateway for controlling the various ZoneMinder
|
||||
# daemons. All starting, stopping and restarting goes through here.
|
||||
# On the first invocation it starts up a server which subsequently
|
||||
# records what's running and what's not. Other invocations just
|
||||
# connect to the server and pass instructions to it.
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmdc.pl - ZoneMinder Daemon Control script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmdc.pl {command} [daemon [options]]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is the gateway for controlling the various ZoneMinder
|
||||
daemons. All starting, stopping and restarting goes through here.
|
||||
On the first invocation it starts up a server which subsequently
|
||||
records what's running and what's not. Other invocations just
|
||||
connect to the server and pass instructions to it.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
{command} - One of 'startup|shutdown|status|check|logrot' or
|
||||
'start|stop|restart|reload|version'.
|
||||
[daemon [options]] - Daemon name and options, required for second group of commands
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -49,6 +66,7 @@ use ZoneMinder;
|
|||
use POSIX;
|
||||
use Socket;
|
||||
use IO::Handle;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
#use Data::Dumper;
|
||||
|
||||
use constant SOCK_FILE => $Config{ZM_PATH_SOCKS}.'/zmdc.sock';
|
||||
|
@ -72,34 +90,22 @@ my @daemons = (
|
|||
'zmtrack.pl'
|
||||
);
|
||||
|
||||
sub Usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmdc.pl <command> [daemon [options]]
|
||||
Parameters are :-
|
||||
<command> - One of 'startup|shutdown|status|check|logrot' or
|
||||
'start|stop|restart|reload|version'.
|
||||
[daemon [options]] - Daemon name and options, required for second group of commands
|
||||
");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
my $command = shift @ARGV;
|
||||
if( !$command )
|
||||
{
|
||||
print( STDERR "No command given\n" );
|
||||
Usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
if ( $command eq 'version' ) {
|
||||
print ZoneMinder::Base::ZM_VERSION."\n";
|
||||
exit( 0 );
|
||||
print ZoneMinder::Base::ZM_VERSION."\n";
|
||||
exit( 0 );
|
||||
}
|
||||
my $needs_daemon = $command !~ /(?:startup|shutdown|status|check|logrot|version)/;
|
||||
my $daemon = shift( @ARGV );
|
||||
if( $needs_daemon && !$daemon )
|
||||
{
|
||||
print( STDERR "No daemon given\n" );
|
||||
Usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
my @args;
|
||||
|
||||
|
@ -113,7 +119,7 @@ if ( $needs_daemon )
|
|||
else
|
||||
{
|
||||
print( STDERR "Invalid daemon '$daemon' specified" );
|
||||
Usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +158,7 @@ if ( !$server_up )
|
|||
print( "Unable to connect to server\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
# The server isn't there
|
||||
# The server isn't there
|
||||
print( "Starting server\n" );
|
||||
close( CLIENT );
|
||||
|
||||
|
@ -235,12 +241,15 @@ sub run
|
|||
|
||||
logInit();
|
||||
|
||||
dPrint( ZoneMinder::Logger::INFO, "Server starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "Server starting at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
."\n"
|
||||
);
|
||||
|
||||
if ( open( PID, ">".ZM_PID ) )
|
||||
if ( open( my $PID, '>', ZM_PID ) )
|
||||
{
|
||||
print( PID $$ );
|
||||
close( PID );
|
||||
print( $PID $$ );
|
||||
close( $PID );
|
||||
}
|
||||
|
||||
killAll( 1 );
|
||||
|
@ -354,7 +363,10 @@ sub run
|
|||
restartPending();
|
||||
}
|
||||
}
|
||||
dPrint( ZoneMinder::Logger::INFO, "Server exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "Server exiting at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
."\n"
|
||||
);
|
||||
unlink( main::SOCK_FILE );
|
||||
unlink( ZM_PID );
|
||||
exit();
|
||||
|
@ -413,7 +425,10 @@ sub start
|
|||
}
|
||||
elsif ( $process->{pid} && $pid_hash{$process->{pid}} )
|
||||
{
|
||||
dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "'$process->{command}' already running at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
|
||||
.", pid = $process->{pid}\n"
|
||||
);
|
||||
return();
|
||||
}
|
||||
|
||||
|
@ -428,7 +443,10 @@ sub start
|
|||
$process->{started} = time();
|
||||
delete( $process->{pending} );
|
||||
|
||||
dPrint( ZoneMinder::Logger::INFO, "'$command' starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "'$command' starting at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
|
||||
.", pid = $process->{pid}\n"
|
||||
);
|
||||
|
||||
$cmd_hash{$process->{command}} = $pid_hash{$cpid} = $process;
|
||||
sigprocmask( SIG_SETMASK, $sigset ) or Fatal( "Can't restore SIGCHLD: $!" );
|
||||
|
@ -437,7 +455,11 @@ sub start
|
|||
{
|
||||
logReinit();
|
||||
|
||||
dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) )."' started at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "'".join( ' ', ( $daemon, @args ) )
|
||||
."' started at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
."\n"
|
||||
);
|
||||
|
||||
if ( $daemon =~ /^${daemon_patt}$/ )
|
||||
{
|
||||
|
@ -501,7 +523,10 @@ sub _stop
|
|||
elsif ( $process->{pending} )
|
||||
{
|
||||
delete( $cmd_hash{$command} );
|
||||
dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "Command '$command' removed from pending list at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
."\n"
|
||||
);
|
||||
return();
|
||||
}
|
||||
|
||||
|
@ -512,7 +537,11 @@ sub _stop
|
|||
return();
|
||||
}
|
||||
|
||||
dPrint( ZoneMinder::Logger::INFO, "'$daemon ".join( ' ', @args )."' stopping at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "'$daemon ".join( ' ', @args )
|
||||
."' stopping at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
."\n"
|
||||
);
|
||||
$process->{keepalive} = !$final;
|
||||
kill( 'TERM', $cpid );
|
||||
delete( $cmd_hash{$command} );
|
||||
|
@ -694,7 +723,10 @@ sub shutdownAll
|
|||
stop( $process->{daemon}, @{$process->{args}} );
|
||||
}
|
||||
killAll( 5 );
|
||||
dPrint( ZoneMinder::Logger::INFO, "Server shutdown at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
dPrint( ZoneMinder::Logger::INFO, "Server shutdown at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
."\n"
|
||||
);
|
||||
unlink( main::SOCK_FILE );
|
||||
unlink( ZM_PID );
|
||||
close( CLIENT );
|
||||
|
@ -750,7 +782,10 @@ sub status
|
|||
|
||||
if ( $process->{pending} )
|
||||
{
|
||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" );
|
||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )
|
||||
."\n"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -761,13 +796,19 @@ sub status
|
|||
return();
|
||||
}
|
||||
}
|
||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}" );
|
||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' running since "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
|
||||
.", pid = $process->{pid}"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach my $process ( values(%pid_hash) )
|
||||
{
|
||||
my $out_str = "'$process->{command}' running since ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) ).", pid = $process->{pid}";
|
||||
my $out_str = "'$process->{command}' running since "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{started}) )
|
||||
.", pid = $process->{pid}"
|
||||
;
|
||||
$out_str .= ", valid" if ( kill( 0, $process->{pid} ) );
|
||||
$out_str .= "\n";
|
||||
dPrint( ZoneMinder::Logger::DEBUG, $out_str );
|
||||
|
@ -776,7 +817,10 @@ sub status
|
|||
{
|
||||
if ( $process->{pending} )
|
||||
{
|
||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at ".strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )."\n" );
|
||||
dPrint( ZoneMinder::Logger::DEBUG, "'$process->{command}' pending at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime( $process->{pending}) )
|
||||
."\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -786,19 +830,23 @@ sub killAll
|
|||
{
|
||||
my $delay = shift;
|
||||
sleep( $delay );
|
||||
my $killall;
|
||||
if ( '@HOST_OS@' eq 'BSD' ) {
|
||||
$killall = 'killall -';
|
||||
} else {
|
||||
$killall = 'killall -q -s ';
|
||||
}
|
||||
foreach my $daemon ( @daemons ) {
|
||||
my $killall;
|
||||
if ( '@HOST_OS@' eq 'BSD' )
|
||||
{
|
||||
$killall = 'killall -';
|
||||
} elsif ( '@HOST_OS@' eq 'solaris' ) {
|
||||
$killall = 'pkill -';
|
||||
} else {
|
||||
$killall = 'killall -q -s ';
|
||||
}
|
||||
foreach my $daemon ( @daemons )
|
||||
{
|
||||
|
||||
my $cmd = $killall ."TERM $daemon";
|
||||
Debug( $cmd );
|
||||
qx( $cmd );
|
||||
}
|
||||
sleep( $delay );
|
||||
my $cmd = $killall ."TERM $daemon";
|
||||
Debug( $cmd );
|
||||
qx( $cmd );
|
||||
}
|
||||
sleep( $delay );
|
||||
foreach my $daemon ( @daemons )
|
||||
{
|
||||
my $cmd = $killall."KILL $daemon";
|
||||
|
|
|
@ -20,11 +20,27 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script continuously monitors the recorded events for the given
|
||||
# monitor and applies any filters which would delete and/or upload
|
||||
# matching events
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmfilter.pl - ZoneMinder tool to filter events
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmfilter.pl [-f <filter name>,--filter=<filter name>] | -v, --version
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script continuously monitors the recorded events for the given
|
||||
monitor and applies any filters which would delete and/or upload
|
||||
matching events.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
-f{filter name}, --filter={filter name} - The name of a specific filter to run
|
||||
-v, --version - Print ZoneMinder version
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -49,9 +65,13 @@ use POSIX;
|
|||
use Time::HiRes qw/gettimeofday/;
|
||||
use Date::Manip;
|
||||
use Getopt::Long;
|
||||
use Data::Dumper;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
|
||||
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
||||
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
|
||||
? $Config{ZM_DIR_EVENTS}
|
||||
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS})
|
||||
;
|
||||
|
||||
logInit();
|
||||
logSetSignal();
|
||||
|
@ -105,7 +125,6 @@ if ( $Config{ZM_OPT_MESSAGE} )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
$| = 1;
|
||||
|
||||
$ENV{PATH} = '/bin:/usr/bin';
|
||||
|
@ -117,16 +136,6 @@ my $event_id = 0;
|
|||
my $filter_parm = "";
|
||||
my $version = 0;
|
||||
|
||||
sub Usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmfilter.pl [-f <filter name>,--filter=<filter name>] | -v, --version
|
||||
Parameters are :-
|
||||
-f<filter name>, --filter=<filter name> - The name of a specific filter to run
|
||||
");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
#
|
||||
# More or less replicates the equivalent PHP function
|
||||
#
|
||||
|
@ -159,13 +168,14 @@ sub DateTimeToSQL
|
|||
return( strftime( "%Y-%m-%d %H:%M:%S", localtime( $dt_val ) ) );
|
||||
}
|
||||
|
||||
if ( !GetOptions( 'filter=s'=>\$filter_parm, version=>\$version ) )
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
GetOptions(
|
||||
'filter=s' =>\$filter_parm,
|
||||
'version' =>\$version
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
if ( $version ) {
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ( ! EVENT_PATH ) {
|
||||
|
@ -196,7 +206,7 @@ my $last_action = 0;
|
|||
|
||||
while( 1 )
|
||||
{
|
||||
my $now = time;
|
||||
my $now = time;
|
||||
if ( ($now - $last_action) > $Config{ZM_FILTER_RELOAD_DELAY} )
|
||||
{
|
||||
Debug( "Reloading filters\n" );
|
||||
|
@ -257,7 +267,7 @@ sub getFilters
|
|||
my $filter_name = shift;
|
||||
|
||||
my @filters;
|
||||
my $sql = "select * from Filters where";
|
||||
my $sql = "SELECT * FROM Filters WHERE";
|
||||
if ( $filter_name )
|
||||
{
|
||||
$sql .= " Name = ? and";
|
||||
|
@ -266,22 +276,56 @@ sub getFilters
|
|||
{
|
||||
$sql .= " Background = 1 and";
|
||||
}
|
||||
$sql .= " (AutoArchive = 1 or AutoVideo = 1 or AutoUpload = 1 or AutoEmail = 1 or AutoMessage = 1 or AutoExecute = 1 or AutoDelete = 1) order by Name";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$sql .= "( AutoArchive = 1
|
||||
or AutoVideo = 1
|
||||
or AutoUpload = 1
|
||||
or AutoEmail = 1
|
||||
or AutoMessage = 1
|
||||
or AutoExecute = 1
|
||||
or AutoDelete = 1
|
||||
) ORDER BY Name";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res;
|
||||
if ( $filter_name )
|
||||
{
|
||||
$res = $sth->execute( $filter_name ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
$res = $sth->execute( $filter_name )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
}
|
||||
else
|
||||
{
|
||||
$res = $sth->execute() or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
}
|
||||
FILTER: while( my $db_filter = $sth->fetchrow_hashref() )
|
||||
{
|
||||
Debug( "Found filter '$db_filter->{Name}'\n" );
|
||||
my $filter_expr = jsonDecode( $db_filter->{Query} );
|
||||
my $sql = "select E.Id,E.MonitorId,M.Name as MonitorName,M.DefaultRate,M.DefaultScale,E.Name,E.Cause,E.Notes,E.StartTime,unix_timestamp(E.StartTime) as Time,E.Length,E.Frames,E.AlarmFrames,E.TotScore,E.AvgScore,E.MaxScore,E.Archived,E.Videoed,E.Uploaded,E.Emailed,E.Messaged,E.Executed from Events as E inner join Monitors as M on M.Id = E.MonitorId";
|
||||
my $sql = "SELECT E.Id,
|
||||
E.MonitorId,
|
||||
M.Name as MonitorName,
|
||||
M.DefaultRate,
|
||||
M.DefaultScale,
|
||||
E.Name,
|
||||
E.Cause,
|
||||
E.Notes,
|
||||
E.StartTime,
|
||||
unix_timestamp(E.StartTime) as Time,
|
||||
E.Length,
|
||||
E.Frames,
|
||||
E.AlarmFrames,
|
||||
E.TotScore,
|
||||
E.AvgScore,
|
||||
E.MaxScore,
|
||||
E.Archived,
|
||||
E.Videoed,
|
||||
E.Uploaded,
|
||||
E.Emailed,
|
||||
E.Messaged,
|
||||
E.Executed
|
||||
FROM Events as E
|
||||
INNER JOIN Monitors as M on M.Id = E.MonitorId
|
||||
";
|
||||
$db_filter->{Sql} = '';
|
||||
|
||||
if ( $filter_expr->{terms} )
|
||||
|
@ -348,7 +392,10 @@ sub getFilters
|
|||
{
|
||||
$value = "'$temp_value'";
|
||||
}
|
||||
elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name' || $filter_expr->{terms}[$i]->{attr} eq 'Cause' || $filter_expr->{terms}[$i]->{attr} eq 'Notes' )
|
||||
elsif ( $filter_expr->{terms}[$i]->{attr} eq 'Name'
|
||||
|| $filter_expr->{terms}[$i]->{attr} eq 'Cause'
|
||||
|| $filter_expr->{terms}[$i]->{attr} eq 'Notes'
|
||||
)
|
||||
{
|
||||
$value = "'$temp_value'";
|
||||
}
|
||||
|
@ -357,7 +404,8 @@ sub getFilters
|
|||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value )
|
||||
{
|
||||
Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" );
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$db_filter->{Name}'\n" );
|
||||
next FILTER;
|
||||
}
|
||||
$value = "'$value'";
|
||||
|
@ -367,7 +415,8 @@ sub getFilters
|
|||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value )
|
||||
{
|
||||
Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" );
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$db_filter->{Name}'\n" );
|
||||
next FILTER;
|
||||
}
|
||||
$value = "to_days( '$value' )";
|
||||
|
@ -377,7 +426,8 @@ sub getFilters
|
|||
$value = DateTimeToSQL( $temp_value );
|
||||
if ( !$value )
|
||||
{
|
||||
Error( "Error parsing date/time '$temp_value', skipping filter '$db_filter->{Name}'\n" );
|
||||
Error( "Error parsing date/time '$temp_value', "
|
||||
."skipping filter '$db_filter->{Name}'\n" );
|
||||
next FILTER;
|
||||
}
|
||||
$value = "extract( hour_second from '$value' )";
|
||||
|
@ -469,7 +519,7 @@ sub getFilters
|
|||
my $sort_column = '';
|
||||
if ( $filter_expr->{sort_field} eq 'Id' )
|
||||
{
|
||||
$sort_column = "E.Id";
|
||||
$sort_column = "E.Id";
|
||||
}
|
||||
elsif ( $filter_expr->{sort_field} eq 'MonitorName' )
|
||||
{
|
||||
|
@ -525,13 +575,15 @@ sub getFilters
|
|||
$script =~ s/\s.*$//;
|
||||
if ( !-e $script )
|
||||
{
|
||||
Error( "Auto execute script '$script' not found, skipping filter '$db_filter->{Name}'\n" );
|
||||
Error( "Auto execute script '$script' not found, "
|
||||
."skipping filter '$db_filter->{Name}'\n" );
|
||||
next FILTER;
|
||||
|
||||
}
|
||||
elsif ( !-x $script )
|
||||
{
|
||||
Error( "Auto execute script '$script' not executable, skipping filter '$db_filter->{Name}'\n" );
|
||||
Error( "Auto execute script '$script' not executable, "
|
||||
."skipping filter '$db_filter->{Name}'\n" );
|
||||
next FILTER;
|
||||
}
|
||||
}
|
||||
|
@ -557,7 +609,7 @@ sub checkFilter
|
|||
"\n"
|
||||
);
|
||||
my $sql = $filter->{Sql};
|
||||
|
||||
|
||||
if ( $filter->{HasDiskPercent} )
|
||||
{
|
||||
my $disk_percent = getDiskPercent();
|
||||
|
@ -574,7 +626,8 @@ sub checkFilter
|
|||
$sql =~ s/zmSystemLoad/$load/g;
|
||||
}
|
||||
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute();
|
||||
if ( !$res )
|
||||
{
|
||||
|
@ -591,8 +644,10 @@ sub checkFilter
|
|||
Info( "Archiving event $event->{Id}\n" );
|
||||
# Do it individually to avoid locking up the table for new events
|
||||
my $sql = "update Events set Archived = 1 where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
}
|
||||
if ( $Config{ZM_OPT_FFMPEG} && $filter->{AutoVideo} )
|
||||
{
|
||||
|
@ -636,18 +691,24 @@ sub checkFilter
|
|||
Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId}\n" );
|
||||
# Do it individually to avoid locking up the table for new events
|
||||
my $sql = "delete from Events where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
|
||||
if ( ! $Config{ZM_OPT_FAST_DELETE} )
|
||||
{
|
||||
my $sql = "delete from Frames where EventId = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
|
||||
$sql = "delete from Stats where EventId = ?";
|
||||
$sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
$sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
$res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
|
||||
deleteEventFiles( $event->{Id}, $event->{MonitorId} );
|
||||
}
|
||||
|
@ -699,7 +760,8 @@ sub generateVideo
|
|||
$format = $ffmpeg_formats[0];
|
||||
}
|
||||
|
||||
my $command = $Config{ZM_PATH_BIN}."/zmvideo.pl -e ".$event->{Id}." -r ".$rate." -s ".$scale." -f ".$format;
|
||||
my $command = $Config{ZM_PATH_BIN}."/zmvideo.pl -e "
|
||||
.$event->{Id}." -r ".$rate." -s ".$scale." -f ".$format;
|
||||
my $output = qx($command);
|
||||
chomp( $output );
|
||||
my $status = $? >> 8;
|
||||
|
@ -719,11 +781,13 @@ sub generateVideo
|
|||
else
|
||||
{
|
||||
my $sql = "update Events set Videoed = 1 where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
if ( wantarray() )
|
||||
{
|
||||
return( $format, sprintf( "%s/%s", getEventPath( $event ), $output ) );
|
||||
return( $format, sprintf( "%s/%s", getEventPath( $event ), $output ) );
|
||||
}
|
||||
}
|
||||
return( 1 );
|
||||
|
@ -741,7 +805,15 @@ sub uploadArchFile
|
|||
}
|
||||
|
||||
my $archFile = $event->{MonitorName}.'-'.$event->{Id};
|
||||
my $archImagePath = getEventPath( $event )."/".(( $Config{ZM_UPLOAD_ARCH_ANALYSE} )?'{*analyse,*capture}':'*capture').".jpg";
|
||||
my $archImagePath = getEventPath( $event )
|
||||
."/"
|
||||
.(
|
||||
( $Config{ZM_UPLOAD_ARCH_ANALYSE} )
|
||||
? '{*analyse,*capture}'
|
||||
: '*capture'
|
||||
)
|
||||
.".jpg"
|
||||
;
|
||||
my @archImageFiles = glob($archImagePath);
|
||||
my $archLocPath;
|
||||
|
||||
|
@ -764,7 +836,10 @@ sub uploadArchFile
|
|||
$archError = 1;
|
||||
last;
|
||||
}
|
||||
$member->desiredCompressionMethod( $Config{ZM_UPLOAD_ARCH_COMPRESS} ? &COMPRESSION_DEFLATED : &COMPRESSION_STORED );
|
||||
$member->desiredCompressionMethod( $Config{ZM_UPLOAD_ARCH_COMPRESS}
|
||||
? &COMPRESSION_DEFLATED
|
||||
: &COMPRESSION_STORED
|
||||
);
|
||||
}
|
||||
if ( !$archError )
|
||||
{
|
||||
|
@ -793,7 +868,12 @@ sub uploadArchFile
|
|||
$archLocPath = $Config{ZM_UPLOAD_LOC_DIR}.'/'.$archFile;
|
||||
Info( "Creating upload file '$archLocPath', ".int(@archImageFiles)." files\n" );
|
||||
|
||||
if ( $archError = !Archive::Tar->create_archive( $archLocPath, $Config{ZM_UPLOAD_ARCH_COMPRESS}, @archImageFiles ) )
|
||||
if ( $archError = !Archive::Tar->create_archive(
|
||||
$archLocPath,
|
||||
$Config{ZM_UPLOAD_ARCH_COMPRESS},
|
||||
@archImageFiles
|
||||
)
|
||||
)
|
||||
{
|
||||
Error( "Tar error: ".Archive::Tar->error()."\n " );
|
||||
}
|
||||
|
@ -808,42 +888,63 @@ sub uploadArchFile
|
|||
if ( $Config{ZM_UPLOAD_PROTOCOL} eq "ftp" )
|
||||
{
|
||||
Info( "Uploading to ".$Config{ZM_UPLOAD_HOST}." using FTP\n" );
|
||||
my $ftp = Net::FTP->new( $Config{ZM_UPLOAD_HOST}, Timeout=>$Config{ZM_UPLOAD_TIMEOUT}, Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE}, Debug=>$Config{ZM_UPLOAD_DEBUG} );
|
||||
my $ftp = Net::FTP->new(
|
||||
$Config{ZM_UPLOAD_HOST},
|
||||
Timeout=>$Config{ZM_UPLOAD_TIMEOUT},
|
||||
Passive=>$Config{ZM_UPLOAD_FTP_PASSIVE},
|
||||
Debug=>$Config{ZM_UPLOAD_DEBUG}
|
||||
);
|
||||
if ( !$ftp )
|
||||
{
|
||||
Error( "Can't create FTP connection: $@" );
|
||||
return( 0 );
|
||||
}
|
||||
$ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} ) or Error( "FTP - Can't login" );
|
||||
$ftp->binary() or Error( "FTP - Can't go binary" );
|
||||
$ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} ) or Error( "FTP - Can't cwd" ) if ( $Config{ZM_UPLOAD_REM_DIR} );
|
||||
$ftp->put( $archLocPath ) or Error( "FTP - Can't upload '$archLocPath'" );
|
||||
$ftp->quit() or Error( "FTP - Can't quit" );
|
||||
$ftp->login( $Config{ZM_UPLOAD_USER}, $Config{ZM_UPLOAD_PASS} )
|
||||
or Error( "FTP - Can't login" );
|
||||
$ftp->binary()
|
||||
or Error( "FTP - Can't go binary" );
|
||||
$ftp->cwd( $Config{ZM_UPLOAD_REM_DIR} )
|
||||
or Error( "FTP - Can't cwd" )
|
||||
if ( $Config{ZM_UPLOAD_REM_DIR} );
|
||||
$ftp->put( $archLocPath )
|
||||
or Error( "FTP - Can't upload '$archLocPath'" );
|
||||
$ftp->quit()
|
||||
or Error( "FTP - Can't quit" );
|
||||
}
|
||||
else
|
||||
{
|
||||
my $host = $Config{ZM_UPLOAD_HOST};
|
||||
$host .= ":".$Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT};
|
||||
$host .= ":".$Config{ZM_UPLOAD_PORT}
|
||||
if $Config{ZM_UPLOAD_PORT};
|
||||
Info( "Uploading to ".$host." using SFTP\n" );
|
||||
my %sftpOptions = ( host=>$Config{ZM_UPLOAD_HOST}, user=>$Config{ZM_UPLOAD_USER} );
|
||||
$sftpOptions{password} = $Config{ZM_UPLOAD_PASS} if $Config{ZM_UPLOAD_PASS};
|
||||
$sftpOptions{port} = $Config{ZM_UPLOAD_PORT} if $Config{ZM_UPLOAD_PORT};
|
||||
$sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT} if $Config{ZM_UPLOAD_TIMEOUT};
|
||||
$sftpOptions{password} = $Config{ZM_UPLOAD_PASS}
|
||||
if $Config{ZM_UPLOAD_PASS};
|
||||
$sftpOptions{port} = $Config{ZM_UPLOAD_PORT}
|
||||
if $Config{ZM_UPLOAD_PORT};
|
||||
$sftpOptions{timeout} = $Config{ZM_UPLOAD_TIMEOUT}
|
||||
if $Config{ZM_UPLOAD_TIMEOUT};
|
||||
$sftpOptions{more} = [ '-o'=>'StrictHostKeyChecking=no' ];
|
||||
$Net::SFTP::Foreign::debug = -1 if $Config{ZM_UPLOAD_DEBUG};
|
||||
$Net::SFTP::Foreign::debug = -1
|
||||
if $Config{ZM_UPLOAD_DEBUG};
|
||||
my $sftp = Net::SFTP::Foreign->new( $Config{ZM_UPLOAD_HOST}, %sftpOptions );
|
||||
if ( $sftp->error )
|
||||
{
|
||||
Error( "Can't create SFTP connection: ".$sftp->error );
|
||||
return( 0 );
|
||||
}
|
||||
$sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} ) or Error( "SFTP - Can't setcwd: ".$sftp->error ) if $Config{ZM_UPLOAD_REM_DIR};
|
||||
$sftp->put( $archLocPath, $archFile ) or Error( "SFTP - Can't upload '$archLocPath': ".$sftp->error );
|
||||
$sftp->setcwd( $Config{ZM_UPLOAD_REM_DIR} )
|
||||
or Error( "SFTP - Can't setcwd: ".$sftp->error )
|
||||
if $Config{ZM_UPLOAD_REM_DIR};
|
||||
$sftp->put( $archLocPath, $archFile )
|
||||
or Error( "SFTP - Can't upload '$archLocPath': ".$sftp->error );
|
||||
}
|
||||
unlink( $archLocPath );
|
||||
my $sql = "update Events set Uploaded = 1 where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
}
|
||||
return( 1 );
|
||||
}
|
||||
|
@ -864,9 +965,28 @@ sub substituteTags
|
|||
if ( $need_monitor )
|
||||
{
|
||||
my $db_now = strftime( "%Y-%m-%d %H:%M:%S", localtime() );
|
||||
my $sql = "select M.Id, count(E.Id) as EventCount, count(if(E.Archived,1,NULL)) as ArchEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL)) as HourEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL)) as DayEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL)) as WeekEventCount, count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL)) as MonthEventCount from Monitors as M left join Events as E on E.MonitorId = M.Id where MonitorId = ? group by E.MonitorId order by Id";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{MonitorId} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sql = "SELECT
|
||||
M.Id,
|
||||
count(E.Id) as EventCount,
|
||||
count(if(E.Archived,1,NULL))
|
||||
as ArchEventCount,
|
||||
count(if(E.StartTime>'$db_now' - INTERVAL 1 HOUR && E.Archived = 0,1,NULL))
|
||||
as HourEventCount,
|
||||
count(if(E.StartTime>'$db_now' - INTERVAL 1 DAY && E.Archived = 0,1,NULL))
|
||||
as DayEventCount,
|
||||
count(if(E.StartTime>'$db_now' - INTERVAL 7 DAY && E.Archived = 0,1,NULL))
|
||||
as WeekEventCount,
|
||||
count(if(E.StartTime>'$db_now' - INTERVAL 1 MONTH && E.Archived = 0,1,NULL))
|
||||
as MonthEventCount
|
||||
FROM Monitors as M LEFT JOIN Events as E on E.MonitorId = M.Id
|
||||
WHERE MonitorId = ?
|
||||
GROUP BY E.MonitorId
|
||||
ORDER BY Id"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{MonitorId} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
$monitor = $sth->fetchrow_hashref();
|
||||
$sth->finish();
|
||||
return() if ( !$monitor );
|
||||
|
@ -879,9 +999,14 @@ sub substituteTags
|
|||
my $max_alarm_score = 0;
|
||||
if ( $need_images )
|
||||
{
|
||||
my $sql = "select * from Frames where EventId = ? and Type = 'Alarm' order by FrameId";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sql = "SELECT * FROM Frames
|
||||
WHERE EventId = ? AND Type = 'Alarm'
|
||||
ORDER BY FrameId"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
while( my $frame = $sth->fetchrow_hashref() )
|
||||
{
|
||||
if ( !$first_alarm_frame )
|
||||
|
@ -929,14 +1054,34 @@ sub substituteTags
|
|||
$text =~ s/%EPIM%/$url?view=frame&mid=$event->{MonitorId}&eid=$event->{Id}&fid=$max_alarm_frame->{FrameId}/g;
|
||||
if ( $attachments_ref && $text =~ s/%EI1%//g )
|
||||
{
|
||||
push( @$attachments_ref, { type=>"image/jpeg", path=>sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", getEventPath( $event ), $first_alarm_frame->{FrameId} ) } );
|
||||
push( @$attachments_ref,
|
||||
{
|
||||
type=>"image/jpeg",
|
||||
path=>sprintf(
|
||||
"%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg",
|
||||
getEventPath( $event ),
|
||||
$first_alarm_frame->{FrameId}
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
if ( $attachments_ref && $text =~ s/%EIM%//g )
|
||||
{
|
||||
# Don't attach the same image twice
|
||||
if ( !@$attachments_ref || ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} ) )
|
||||
if ( !@$attachments_ref
|
||||
|| ($first_alarm_frame->{FrameId} != $max_alarm_frame->{FrameId} )
|
||||
)
|
||||
{
|
||||
push( @$attachments_ref, { type=>"image/jpeg", path=>sprintf( "%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg", getEventPath( $event ), $max_alarm_frame->{FrameId} ) } );
|
||||
push( @$attachments_ref,
|
||||
{
|
||||
type=>"image/jpeg",
|
||||
path=>sprintf(
|
||||
"%s/%0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg",
|
||||
getEventPath( $event ),
|
||||
$max_alarm_frame->{FrameId}
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -964,7 +1109,7 @@ sub substituteTags
|
|||
$text =~ s/%FN%/$filter->{Name}/g;
|
||||
( my $filter_name = $filter->{Name} ) =~ s/ /+/g;
|
||||
$text =~ s/%FP%/$url?view=filter&mid=$event->{MonitorId}&filter_name=$filter_name/g;
|
||||
|
||||
|
||||
return( $text );
|
||||
}
|
||||
|
||||
|
@ -1023,7 +1168,7 @@ sub sendEmail
|
|||
### Send the Message
|
||||
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 );
|
||||
$mail->send();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my $mail = MIME::Entity->build(
|
||||
|
@ -1056,8 +1201,10 @@ sub sendEmail
|
|||
Info( "Notification email sent\n" );
|
||||
}
|
||||
my $sql = "update Events set Emailed = 1 where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
@ -1117,7 +1264,7 @@ sub sendMessage
|
|||
### Send the Message
|
||||
MIME::Lite->send( "smtp", $Config{ZM_EMAIL_HOST}, Timeout=>60 );
|
||||
$mail->send();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my $mail = MIME::Entity->build(
|
||||
|
@ -1137,7 +1284,9 @@ sub sendMessage
|
|||
Encoding => "base64"
|
||||
);
|
||||
}
|
||||
$mail->smtpsend( Host => $Config{ZM_EMAIL_HOST}, MailFrom => $Config{ZM_FROM_EMAIL} );
|
||||
$mail->smtpsend( Host => $Config{ZM_EMAIL_HOST},
|
||||
MailFrom => $Config{ZM_FROM_EMAIL}
|
||||
);
|
||||
}
|
||||
};
|
||||
if ( $@ )
|
||||
|
@ -1150,8 +1299,10 @@ sub sendMessage
|
|||
Info( "Notification message sent\n" );
|
||||
}
|
||||
my $sql = "update Events set Messaged = 1 where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
@ -1182,8 +1333,10 @@ sub executeCommand
|
|||
else
|
||||
{
|
||||
my $sql = "update Events set Executed = 1 where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $event->{Id} )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
}
|
||||
return( 1 );
|
||||
}
|
||||
|
|
|
@ -20,10 +20,21 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script is used to start and stop the ZoneMinder package primarily to
|
||||
# allow command line control for automatic restart on reboot (see zm script)
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmpkg.pl - ZoneMinder Package Control Script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmpkg.pl {start|stop|restart|status|logrot|'state'|version}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is used to start and stop the ZoneMinder package primarily to
|
||||
allow command line control for automatic restart on reboot (see zm script)
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -38,6 +49,7 @@ use ZoneMinder;
|
|||
use DBI;
|
||||
use POSIX;
|
||||
use Time::HiRes qw/gettimeofday/;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
|
||||
# Detaint our environment
|
||||
$ENV{PATH} = '/bin:/usr/bin';
|
||||
|
@ -46,10 +58,10 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
|||
|
||||
logInit();
|
||||
|
||||
my $command = $ARGV[0];
|
||||
my $command = $ARGV[0]||'';
|
||||
if ( $command eq 'version' ) {
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
my $state;
|
||||
|
@ -58,39 +70,43 @@ my $dbh;
|
|||
|
||||
if ( !$command || $command !~ /^(?:start|stop|restart|status|logrot|version)$/ )
|
||||
{
|
||||
if ( $command )
|
||||
{
|
||||
$dbh = zmDbConnect();
|
||||
# Check to see if it's a valid run state
|
||||
my $sql = 'select * from States where Name = ?';
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $command ) or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
if ( $state = $sth->fetchrow_hashref() )
|
||||
{
|
||||
$state->{Name} = $command;
|
||||
$state->{Definitions} = [];
|
||||
foreach( split( /,/, $state->{Definition} ) )
|
||||
{
|
||||
my ( $id, $function, $enabled ) = split( /:/, $_ );
|
||||
push( @{$state->{Definitions}}, { Id=>$id, Function=>$function, Enabled=>$enabled } );
|
||||
}
|
||||
$command = 'state';
|
||||
}
|
||||
else
|
||||
{
|
||||
$command = undef;
|
||||
}
|
||||
}
|
||||
if ( !$command )
|
||||
{
|
||||
print( "Usage: zmpkg.pl <start|stop|restart|status|logrot|'state'|version>\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
if ( $command )
|
||||
{
|
||||
$dbh = zmDbConnect();
|
||||
# Check to see if it's a valid run state
|
||||
my $sql = 'select * from States where Name = ?';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $command )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
if ( $state = $sth->fetchrow_hashref() )
|
||||
{
|
||||
$state->{Name} = $command;
|
||||
$state->{Definitions} = [];
|
||||
foreach( split( /,/, $state->{Definition} ) )
|
||||
{
|
||||
my ( $id, $function, $enabled ) = split( /:/, $_ );
|
||||
push( @{$state->{Definitions}},
|
||||
{ Id=>$id, Function=>$function, Enabled=>$enabled }
|
||||
);
|
||||
}
|
||||
$command = 'state';
|
||||
}
|
||||
else
|
||||
{
|
||||
$command = undef;
|
||||
}
|
||||
}
|
||||
if ( !$command )
|
||||
{
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
}
|
||||
$dbh = zmDbConnect() if ! $dbh;
|
||||
|
||||
# Move to the right place
|
||||
chdir( $Config{ZM_PATH_WEB} ) or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" );
|
||||
chdir( $Config{ZM_PATH_WEB} )
|
||||
or Fatal( "Can't chdir to '".$Config{ZM_PATH_WEB}."': $!" );
|
||||
|
||||
my $dbg_id = "";
|
||||
|
||||
|
@ -100,209 +116,232 @@ my $retval = 0;
|
|||
|
||||
if ( $command eq "state" )
|
||||
{
|
||||
Info( "Updating DB: $state->{Name}\n" );
|
||||
my $sql = "select * from Monitors order by Id asc";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
foreach my $definition ( @{$state->{Definitions}} )
|
||||
{
|
||||
if ( $monitor->{Id} =~ /^$definition->{Id}$/ )
|
||||
{
|
||||
$monitor->{NewFunction} = $definition->{Function};
|
||||
$monitor->{NewEnabled} = $definition->{Enabled};
|
||||
}
|
||||
}
|
||||
#next if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewFunction} = 'None' if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewEnabled} = 0 if ( !$monitor->{NewEnabled} );
|
||||
if ( $monitor->{Function} ne $monitor->{NewFunction} || $monitor->{Enabled} ne $monitor->{NewEnabled} )
|
||||
{
|
||||
my $sql = "update Monitors set Function = ?, Enabled = ? where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} ) or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
}
|
||||
$sth->finish();
|
||||
Info( "Updating DB: $state->{Name}\n" );
|
||||
my $sql = "select * from Monitors order by Id asc";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
foreach my $definition ( @{$state->{Definitions}} )
|
||||
{
|
||||
if ( $monitor->{Id} =~ /^$definition->{Id}$/ )
|
||||
{
|
||||
$monitor->{NewFunction} = $definition->{Function};
|
||||
$monitor->{NewEnabled} = $definition->{Enabled};
|
||||
}
|
||||
}
|
||||
#next if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewFunction} = 'None'
|
||||
if ( !$monitor->{NewFunction} );
|
||||
$monitor->{NewEnabled} = 0
|
||||
if ( !$monitor->{NewEnabled} );
|
||||
if ( $monitor->{Function} ne $monitor->{NewFunction}
|
||||
|| $monitor->{Enabled} ne $monitor->{NewEnabled}
|
||||
)
|
||||
{
|
||||
my $sql = "update Monitors set Function = ?, Enabled = ? where Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id} )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
}
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
$command = "restart";
|
||||
$command = "restart";
|
||||
}
|
||||
|
||||
# Check if we are running systemd and if we have been called by the system
|
||||
if ( $command =~ /^(start|stop|restart)$/ )
|
||||
{
|
||||
# We have to detaint to keep perl from complaining
|
||||
$command = $1;
|
||||
# We have to detaint to keep perl from complaining
|
||||
$command = $1;
|
||||
|
||||
if ( systemdRunning() && !calledBysystem() ) {
|
||||
qx(@BINDIR@/zmsystemctl.pl $command);
|
||||
$command = "";
|
||||
}
|
||||
if ( systemdRunning() && !calledBysystem() ) {
|
||||
qx(@BINDIR@/zmsystemctl.pl $command);
|
||||
$command = "";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $command =~ /^(?:stop|restart)$/ )
|
||||
{
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
|
||||
if ( $status eq "running" )
|
||||
{
|
||||
runCommand( "zmdc.pl shutdown" );
|
||||
zmMemTidy();
|
||||
}
|
||||
else
|
||||
{
|
||||
$retval = 1;
|
||||
}
|
||||
if ( $status eq "running" )
|
||||
{
|
||||
runCommand( "zmdc.pl shutdown" );
|
||||
zmMemTidy();
|
||||
}
|
||||
else
|
||||
{
|
||||
$retval = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#runCommand( "zmupdate.pl -f" );
|
||||
|
||||
if ( $command =~ /^(?:start|restart)$/ )
|
||||
{
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
|
||||
if ( $status eq "stopped" )
|
||||
{
|
||||
if ( $Config{ZM_DYN_DB_VERSION} and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION ) )
|
||||
if ( $status eq "stopped" )
|
||||
{
|
||||
if ( $Config{ZM_DYN_DB_VERSION}
|
||||
and ( $Config{ZM_DYN_DB_VERSION} ne ZM_VERSION )
|
||||
)
|
||||
{
|
||||
Fatal( "Version mismatch, system is version ".ZM_VERSION.", database is ".$Config{ZM_DYN_DB_VERSION}.", please run zmupdate.pl to update." );
|
||||
Fatal( "Version mismatch, system is version ".ZM_VERSION
|
||||
.", database is ".$Config{ZM_DYN_DB_VERSION}
|
||||
.", please run zmupdate.pl to update."
|
||||
);
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
# Recreate the temporary directory if it's been wiped
|
||||
verifyFolder("@ZM_TMPDIR@");
|
||||
verifyFolder("@ZM_TMPDIR@");
|
||||
|
||||
# Recreate the run directory if it's been wiped
|
||||
verifyFolder("@ZM_RUNDIR@");
|
||||
verifyFolder("@ZM_RUNDIR@");
|
||||
|
||||
# Recreate the sock directory if it's been wiped
|
||||
verifyFolder("@ZM_SOCKDIR@");
|
||||
verifyFolder("@ZM_SOCKDIR@");
|
||||
|
||||
zmMemTidy();
|
||||
runCommand( "zmdc.pl startup" );
|
||||
zmMemTidy();
|
||||
runCommand( "zmdc.pl startup" );
|
||||
|
||||
my $sql = "select * from Monitors";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
if ( $monitor->{Function} ne 'None' )
|
||||
{
|
||||
if ( $monitor->{Type} eq 'Local' )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
|
||||
}
|
||||
else
|
||||
{
|
||||
runCommand( "zmdc.pl start zmc -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $monitor->{Function} ne 'Monitor' )
|
||||
{
|
||||
if ( $Config{ZM_OPT_FRAME_SERVER} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmf -m $monitor->{Id}" );
|
||||
}
|
||||
runCommand( "zmdc.pl start zma -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_CONTROL} )
|
||||
{
|
||||
if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' )
|
||||
{
|
||||
if ( $monitor->{Controllable} && $monitor->{TrackMotion} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$sth->finish();
|
||||
my $sql = "select * from Monitors";
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
if ( $monitor->{Function} ne 'None' )
|
||||
{
|
||||
if ( $monitor->{Type} eq 'Local' )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmc -d $monitor->{Device}" );
|
||||
}
|
||||
else
|
||||
{
|
||||
runCommand( "zmdc.pl start zmc -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $monitor->{Function} ne 'Monitor' )
|
||||
{
|
||||
if ( $Config{ZM_OPT_FRAME_SERVER} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmf -m $monitor->{Id}" );
|
||||
}
|
||||
runCommand( "zmdc.pl start zma -m $monitor->{Id}" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_CONTROL} )
|
||||
{
|
||||
if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' )
|
||||
{
|
||||
if ( $monitor->{Controllable} && $monitor->{TrackMotion} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmtrack.pl -m $monitor->{Id}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$sth->finish();
|
||||
|
||||
# This is now started unconditionally
|
||||
runCommand( "zmdc.pl start zmfilter.pl" );
|
||||
if ( $Config{ZM_RUN_AUDIT} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmaudit.pl -c" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_TRIGGERS} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmtrigger.pl" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_X10} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmx10.pl -c start" );
|
||||
}
|
||||
runCommand( "zmdc.pl start zmwatch.pl" );
|
||||
if ( $Config{ZM_CHECK_FOR_UPDATES} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmupdate.pl -c" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$retval = 1;
|
||||
}
|
||||
# This is now started unconditionally
|
||||
runCommand( "zmdc.pl start zmfilter.pl" );
|
||||
if ( $Config{ZM_RUN_AUDIT} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmaudit.pl -c" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_TRIGGERS} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmtrigger.pl" );
|
||||
}
|
||||
if ( $Config{ZM_OPT_X10} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmx10.pl -c start" );
|
||||
}
|
||||
runCommand( "zmdc.pl start zmwatch.pl" );
|
||||
if ( $Config{ZM_CHECK_FOR_UPDATES} )
|
||||
{
|
||||
runCommand( "zmdc.pl start zmupdate.pl -c" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$retval = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $command eq "status" )
|
||||
{
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
my $status = runCommand( "zmdc.pl check" );
|
||||
|
||||
print( STDOUT $status."\n" );
|
||||
print( STDOUT $status."\n" );
|
||||
}
|
||||
|
||||
if ( $command eq "logrot" )
|
||||
{
|
||||
runCommand( "zmdc.pl logrot" );
|
||||
runCommand( "zmdc.pl logrot" );
|
||||
}
|
||||
|
||||
exit( $retval );
|
||||
|
||||
sub systemdRunning
|
||||
{
|
||||
my $result = 0;
|
||||
my $result = 0;
|
||||
|
||||
my $output = qx(ps -o comm="" 1);
|
||||
chomp( $output );
|
||||
my $output = qx(ps -o comm="" -p 1);
|
||||
chomp( $output );
|
||||
|
||||
if ($output =~ /systemd/) {
|
||||
$result = 1;
|
||||
}
|
||||
if ($output =~ /systemd/) {
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub calledBysystem
|
||||
{
|
||||
my $result = 0;
|
||||
my $ppid = getppid();
|
||||
my $result = 0;
|
||||
my $ppid = getppid();
|
||||
|
||||
my $output = qx(ps -o comm="" $ppid);
|
||||
chomp( $output );
|
||||
my $output = qx(ps -o comm="" -p $ppid);
|
||||
chomp( $output );
|
||||
|
||||
if ($output =~ /^(?:systemd|init)$/) {
|
||||
$result = 1;
|
||||
}
|
||||
if ($output =~ /^(?:systemd|init)$/) {
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub verifyFolder
|
||||
{
|
||||
my $folder = shift;
|
||||
my $folder = shift;
|
||||
|
||||
# Recreate the temporary directory if it's been wiped
|
||||
if ( !-e $folder )
|
||||
{
|
||||
Debug( "Recreating directory '$folder'" );
|
||||
mkdir( "$folder", 0774 ) or Fatal( "Can't create missing temporary directory '$folder': $!" );
|
||||
mkdir( "$folder", 0774 )
|
||||
or Fatal( "Can't create missing temporary directory '$folder': $!" );
|
||||
my ( $runName ) = getpwuid( $> );
|
||||
if ( $runName ne $Config{ZM_WEB_USER} )
|
||||
{
|
||||
# Not running as web user, so should be root in which case chown the directory
|
||||
my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} ) or Fatal( "Can't get user details for web user '".$Config{ZM_WEB_USER}."': $!" );
|
||||
chown( $webUid, $webGid, "$folder" ) or Fatal( "Can't change ownership of directory '$folder' to '".$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!" );
|
||||
# Not running as web user, so should be root in which case
|
||||
# chown the directory
|
||||
my ( $webName, $webPass, $webUid, $webGid ) = getpwnam( $Config{ZM_WEB_USER} )
|
||||
or Fatal( "Can't get user details for web user '"
|
||||
.$Config{ZM_WEB_USER}."': $!"
|
||||
);
|
||||
chown( $webUid, $webGid, "$folder" )
|
||||
or Fatal( "Can't change ownership of directory '$folder' to '"
|
||||
.$Config{ZM_WEB_USER}.":".$Config{ZM_WEB_GROUP}."': $!"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder Update Script, $Date$, $Revision$
|
||||
# ZoneMinder systemctl wrapper, $Date$, $Revision$
|
||||
# Copyright (C) 2001-2008 Philip Coombes
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
@ -20,25 +20,39 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This is a wrapper script that allows zoneminder to start and stop itself
|
||||
# in a manner that keeps it in-sync with systemd. This script is intended
|
||||
# to be called internally by zoneminder and may not give the desired results
|
||||
# if run from the command line.
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmsystemctl.pl - ZoneMinder systemctl wrapper
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmsystemctl.pl {start|stop|restart|version}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a wrapper script that allows zoneminder to start and stop itself
|
||||
in a manner that keeps it in-sync with systemd. This script is intended
|
||||
to be called internally by zoneminder and may not give the desired results
|
||||
if run from the command line.
|
||||
|
||||
=cut
|
||||
use warnings;
|
||||
use strict;
|
||||
use bytes;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
|
||||
@EXTRA_PERL_LIB@
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
|
||||
my $command = $ARGV[0];
|
||||
|
||||
if ( (scalar(@ARGV) == 1) && ($command =~ /^(start|stop|restart|version)$/ )) {
|
||||
$command = $1;
|
||||
if ( (scalar(@ARGV) == 1)
|
||||
&& ($command =~ /^(start|stop|restart|version)$/ )
|
||||
){
|
||||
$command = $1;
|
||||
} else {
|
||||
die(" USAGE: zmsystemctl.pl <start|stop|restart|version>\n");
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
my $path = qx(which systemctl);
|
||||
|
@ -46,7 +60,7 @@ chomp($path);
|
|||
|
||||
my $status = $? >> 8;
|
||||
if ( !$path || $status ) {
|
||||
Fatal( "Unable to determine systemctl executable. Is systemd in use?" );
|
||||
Fatal( "Unable to determine systemctl executable. Is systemd in use?" );
|
||||
}
|
||||
|
||||
Info( "Redirecting command through systemctl\n" );
|
||||
|
|
|
@ -20,10 +20,26 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script is used to trigger and cancel alarms from external sources
|
||||
# using an arbitrary text based format
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmtrack.pl - ZoneMinder Experimental PTZ Tracking Script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmtrack.pl -m <monitor>
|
||||
zmtrack.pl --monitor=<monitor>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
-m<monitor>, --monitor=<monitor> - Id of the monitor to track
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is used to trigger and cancel alarms from external sources
|
||||
using an arbitrary text based format.
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -45,8 +61,9 @@ use constant SLEEP_TIME => 10000; # In microseconds
|
|||
use ZoneMinder;
|
||||
use DBI;
|
||||
use POSIX;
|
||||
use Data::Dumper;
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
use Getopt::Long;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
use Time::HiRes qw( usleep );
|
||||
|
||||
$| = 1;
|
||||
|
@ -57,20 +74,8 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
|||
|
||||
my $mid = 0;
|
||||
|
||||
sub Usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmtrack.pl -m <monitor>,--monitor=<monitor>]
|
||||
Parameters are :-
|
||||
-m<monitor>, --monitor=<monitor> - Id of the monitor to track
|
||||
");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
if ( !GetOptions( 'monitor=s'=>\$mid ) )
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
GetOptions( 'monitor=s'=>\$mid )
|
||||
or pod2usage(-exitstatus => -1);
|
||||
|
||||
logInit();
|
||||
logSetSignal();
|
||||
|
@ -78,44 +83,52 @@ logSetSignal();
|
|||
my ( $detaint_mid ) = $mid =~ /^(\d+)$/;
|
||||
$mid = $detaint_mid;
|
||||
|
||||
print( "Tracker daemon $mid (experimental) starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
||||
print( "Tracker daemon $mid (experimental) starting at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
."\n"
|
||||
);
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
|
||||
my $sql = "select C.*,M.* from Monitors as M left join Controls as C on M.ControlId = C.Id where M.Id = ?";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $sql = "SELECT C.*,M.* FROM Monitors as M
|
||||
LEFT JOIN Controls as C on M.ControlId = C.Id
|
||||
WHERE M.Id = ?"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
|
||||
my $res = $sth->execute( $mid ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $res = $sth->execute( $mid )
|
||||
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||
my $monitor = $sth->fetchrow_hashref();
|
||||
|
||||
if ( !$monitor )
|
||||
{
|
||||
print( "Can't find monitor '$mid'\n" );
|
||||
exit( -1 );
|
||||
print( "Can't find monitor '$mid'\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
if ( !$monitor->{Controllable} )
|
||||
{
|
||||
print( "Monitor '$mid' is not controllable\n" );
|
||||
exit( -1 );
|
||||
print( "Monitor '$mid' is not controllable\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
if ( !$monitor->{TrackMotion} )
|
||||
{
|
||||
print( "Monitor '$mid' is not configured to track motion\n" );
|
||||
exit( -1 );
|
||||
print( "Monitor '$mid' is not configured to track motion\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
if ( !$monitor->{CanMoveMap} )
|
||||
{
|
||||
print( "Monitor '$mid' cannot move in map mode" );
|
||||
if ( $monitor->{CanMoveRel} )
|
||||
{
|
||||
print( ", falling back to pseudo map mode\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
print( "\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
print( "Monitor '$mid' cannot move in map mode" );
|
||||
if ( $monitor->{CanMoveRel} )
|
||||
{
|
||||
print( ", falling back to pseudo map mode\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
print( "\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
}
|
||||
|
||||
Debug( "Found monitor for id '$monitor'\n" );
|
||||
|
@ -123,84 +136,100 @@ exit( -1 ) if ( !zmMemVerify( $monitor ) );
|
|||
|
||||
sub Suspend
|
||||
{
|
||||
my $monitor = shift;
|
||||
zmMonitorSuspend( $monitor );
|
||||
my $monitor = shift;
|
||||
zmMonitorSuspend( $monitor );
|
||||
}
|
||||
|
||||
sub Resume
|
||||
{
|
||||
my $monitor = shift;
|
||||
sleep( $monitor->{TrackDelay} );
|
||||
zmMonitorResume( $monitor );
|
||||
my $monitor = shift;
|
||||
sleep( $monitor->{TrackDelay} );
|
||||
zmMonitorResume( $monitor );
|
||||
}
|
||||
|
||||
sub Track
|
||||
{
|
||||
my $monitor = shift;
|
||||
my ( $x, $y ) = @_;
|
||||
my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x;
|
||||
my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y;
|
||||
my $monitor = shift;
|
||||
my ( $x, $y ) = @_;
|
||||
my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x;
|
||||
my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y;
|
||||
|
||||
my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id};
|
||||
$ctrlCommand .= " --command=".($monitor->{CanMoveMap}?"moveMap":"movePseudoMap")." --xcoord=$x --ycoord=$y";
|
||||
executeShellCommand( $ctrlCommand );
|
||||
my $ctrlCommand = $Config{ZM_PATH_BIN}
|
||||
."/zmcontrol.pl -i "
|
||||
.$monitor->{Id}
|
||||
;
|
||||
$ctrlCommand .= " --command="
|
||||
.( $monitor->{CanMoveMap} ? "moveMap"
|
||||
: "movePseudoMap"
|
||||
)
|
||||
." --xcoord=$x --ycoord=$y"
|
||||
;
|
||||
executeShellCommand( $ctrlCommand );
|
||||
}
|
||||
|
||||
sub Return
|
||||
{
|
||||
my $monitor = shift;
|
||||
my $monitor = shift;
|
||||
|
||||
my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id};
|
||||
if ( $monitor->{ReturnLocation} > 0 )
|
||||
{
|
||||
$ctrlCommand .= " --command=presetGoto --preset=".$monitor->{ReturnLocation};
|
||||
}
|
||||
else
|
||||
{
|
||||
$ctrlCommand .= " --command=presetHome";
|
||||
}
|
||||
executeShellCommand( $ctrlCommand );
|
||||
my $ctrlCommand = $Config{ZM_PATH_BIN}
|
||||
."/zmcontrol.pl -i "
|
||||
.$monitor->{Id}
|
||||
;
|
||||
if ( $monitor->{ReturnLocation} > 0 )
|
||||
{
|
||||
$ctrlCommand .= " --command=presetGoto --preset="
|
||||
.$monitor->{ReturnLocation}
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ctrlCommand .= " --command=presetHome";
|
||||
}
|
||||
executeShellCommand( $ctrlCommand );
|
||||
}
|
||||
|
||||
my $last_alarm = 0;
|
||||
if ( ($monitor->{ReturnLocation} >= 0) )
|
||||
{
|
||||
Suspend( $monitor );
|
||||
Return( $monitor );
|
||||
Resume( $monitor );
|
||||
Suspend( $monitor );
|
||||
Return( $monitor );
|
||||
Resume( $monitor );
|
||||
}
|
||||
|
||||
my $alarmed = undef;
|
||||
while( 1 )
|
||||
{
|
||||
if ( zmIsAlarmed( $monitor ) )
|
||||
{
|
||||
my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor );
|
||||
if ( $alarm_x >= 0 && $alarm_y >= 0 )
|
||||
{
|
||||
Debug( "Got alarm at $alarm_x, $alarm_y\n" );
|
||||
Suspend( $monitor );
|
||||
Track( $monitor, $alarm_x, $alarm_y );
|
||||
Resume( $monitor );
|
||||
$last_alarm = time();
|
||||
$alarmed = !undef;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( logDebugging() && $alarmed )
|
||||
{
|
||||
print( "Left alarm state\n" );
|
||||
$alarmed = undef;
|
||||
}
|
||||
if ( ($monitor->{ReturnLocation} >= 0) && ($last_alarm > 0) && ((time()-$last_alarm) > $monitor->{ReturnDelay}) )
|
||||
{
|
||||
Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" );
|
||||
Suspend( $monitor );
|
||||
Return( $monitor );
|
||||
Resume( $monitor );
|
||||
$last_alarm = 0;
|
||||
}
|
||||
}
|
||||
usleep( SLEEP_TIME );
|
||||
if ( zmIsAlarmed( $monitor ) )
|
||||
{
|
||||
my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor );
|
||||
if ( $alarm_x >= 0 && $alarm_y >= 0 )
|
||||
{
|
||||
Debug( "Got alarm at $alarm_x, $alarm_y\n" );
|
||||
Suspend( $monitor );
|
||||
Track( $monitor, $alarm_x, $alarm_y );
|
||||
Resume( $monitor );
|
||||
$last_alarm = time();
|
||||
$alarmed = !undef;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( logDebugging() && $alarmed )
|
||||
{
|
||||
print( "Left alarm state\n" );
|
||||
$alarmed = undef;
|
||||
}
|
||||
if ( ($monitor->{ReturnLocation} >= 0)
|
||||
&& ($last_alarm > 0)
|
||||
&& ((time()-$last_alarm) > $monitor->{ReturnDelay})
|
||||
)
|
||||
{
|
||||
Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" );
|
||||
Suspend( $monitor );
|
||||
Return( $monitor );
|
||||
Resume( $monitor );
|
||||
$last_alarm = 0;
|
||||
}
|
||||
}
|
||||
usleep( SLEEP_TIME );
|
||||
}
|
||||
|
|
|
@ -20,11 +20,17 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script is used to trigger and cancel alarms from external connections
|
||||
# using an arbitrary text based format
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmtrigger.pl - ZoneMinder External Trigger Script
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is used to trigger and cancel alarms from external connections
|
||||
using an arbitrary text based format
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -52,8 +58,22 @@ use ZoneMinder::Trigger::Channel::Serial;
|
|||
use ZoneMinder::Trigger::Connection;
|
||||
|
||||
my @connections;
|
||||
push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan1", channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ), mode=>"rw" ) );
|
||||
push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel=>ZoneMinder::Trigger::Channel::Unix->new( path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock' ), mode=>"rw" ) );
|
||||
push( @connections,
|
||||
ZoneMinder::Trigger::Connection->new(
|
||||
name=>"Chan1",
|
||||
channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ),
|
||||
mode=>"rw"
|
||||
)
|
||||
);
|
||||
push( @connections,
|
||||
ZoneMinder::Trigger::Connection->new(
|
||||
name=>"Chan2",
|
||||
channel=>ZoneMinder::Trigger::Channel::Unix->new(
|
||||
path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock'
|
||||
),
|
||||
mode=>"rw"
|
||||
)
|
||||
);
|
||||
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan3", channel=>ZoneMinder::Trigger::Channel::File->new( path=>'/tmp/zmtrigger.out' ), mode=>"w" ) );
|
||||
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan4", channel=>ZoneMinder::Trigger::Channel::Serial->new( path=>'/dev/ttyS0' ), mode=>"rw" ) );
|
||||
|
||||
|
@ -65,7 +85,7 @@ push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel
|
|||
|
||||
use DBI;
|
||||
#use Socket;
|
||||
use Data::Dumper;
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
use POSIX qw( EINTR );
|
||||
use Time::HiRes qw( usleep );
|
||||
|
||||
|
@ -85,8 +105,8 @@ my $dbh = zmDbConnect();
|
|||
my $base_rin = '';
|
||||
foreach my $connection ( @connections )
|
||||
{
|
||||
Info( "Opening connection '$connection->{name}'\n" );
|
||||
$connection->open();
|
||||
Info( "Opening connection '$connection->{name}'\n" );
|
||||
$connection->open();
|
||||
}
|
||||
|
||||
my @in_select_connections = grep { $_->input() && $_->selectable() } @connections;
|
||||
|
@ -95,7 +115,7 @@ my @out_connections = grep { $_->output() } @connections;
|
|||
|
||||
foreach my $connection ( @in_select_connections )
|
||||
{
|
||||
vec( $base_rin, $connection->fileno(), 1 ) = 1;
|
||||
vec( $base_rin, $connection->fileno(), 1 ) = 1;
|
||||
}
|
||||
|
||||
my %spawned_connections;
|
||||
|
@ -111,332 +131,387 @@ my $timeout = SELECT_TIMEOUT;
|
|||
my %actions;
|
||||
while( 1 )
|
||||
{
|
||||
$rin = $base_rin;
|
||||
# Add the file descriptors of any spawned connections
|
||||
foreach my $fileno ( keys(%spawned_connections) )
|
||||
{
|
||||
vec( $rin, $fileno, 1 ) = 1;
|
||||
}
|
||||
$rin = $base_rin;
|
||||
# Add the file descriptors of any spawned connections
|
||||
foreach my $fileno ( keys(%spawned_connections) )
|
||||
{
|
||||
vec( $rin, $fileno, 1 ) = 1;
|
||||
}
|
||||
|
||||
my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout );
|
||||
if ( $nfound > 0 )
|
||||
{
|
||||
Debug( "Got input from $nfound connections\n" );
|
||||
foreach my $connection ( @in_select_connections )
|
||||
{
|
||||
if ( vec( $rout, $connection->fileno(), 1 ) )
|
||||
{
|
||||
Debug( "Got input from connection ".$connection->name()." (".$connection->fileno().")\n" );
|
||||
if ( $connection->spawns() )
|
||||
{
|
||||
my $new_connection = $connection->accept();
|
||||
$spawned_connections{$new_connection->fileno()} = $new_connection;
|
||||
Debug( "Added new spawned connection (".$new_connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
my $messages = $connection->getMessages();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach my $connection ( values(%spawned_connections) )
|
||||
{
|
||||
if ( vec( $rout, $connection->fileno(), 1 ) )
|
||||
{
|
||||
Debug( "Got input from spawned connection ".$connection->name()." (".$connection->fileno().")\n" );
|
||||
my $messages = $connection->getMessages();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete( $spawned_connections{$connection->fileno()} );
|
||||
Debug( "Removed spawned connection (".$connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" );
|
||||
$connection->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ( $nfound < 0 )
|
||||
{
|
||||
if ( $! == EINTR )
|
||||
{
|
||||
# Do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
Fatal( "Can't select: $!" );
|
||||
}
|
||||
}
|
||||
my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout );
|
||||
if ( $nfound > 0 )
|
||||
{
|
||||
Debug( "Got input from $nfound connections\n" );
|
||||
foreach my $connection ( @in_select_connections )
|
||||
{
|
||||
if ( vec( $rout, $connection->fileno(), 1 ) )
|
||||
{
|
||||
Debug( "Got input from connection "
|
||||
.$connection->name()
|
||||
." ("
|
||||
.$connection->fileno()
|
||||
.")\n"
|
||||
);
|
||||
if ( $connection->spawns() )
|
||||
{
|
||||
my $new_connection = $connection->accept();
|
||||
$spawned_connections{$new_connection->fileno()} = $new_connection;
|
||||
Debug( "Added new spawned connection ("
|
||||
.$new_connection->fileno()
|
||||
."), "
|
||||
.int(keys(%spawned_connections))
|
||||
." spawned connections\n"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
my $messages = $connection->getMessages();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach my $connection ( values(%spawned_connections) )
|
||||
{
|
||||
if ( vec( $rout, $connection->fileno(), 1 ) )
|
||||
{
|
||||
Debug( "Got input from spawned connection "
|
||||
.$connection->name()
|
||||
." ("
|
||||
.$connection->fileno()
|
||||
.")\n"
|
||||
);
|
||||
my $messages = $connection->getMessages();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete( $spawned_connections{$connection->fileno()} );
|
||||
Debug( "Removed spawned connection ("
|
||||
.$connection->fileno()
|
||||
."), "
|
||||
.int(keys(%spawned_connections))
|
||||
." spawned connections\n"
|
||||
);
|
||||
$connection->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ( $nfound < 0 )
|
||||
{
|
||||
if ( $! == EINTR )
|
||||
{
|
||||
# Do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
Fatal( "Can't select: $!" );
|
||||
}
|
||||
}
|
||||
|
||||
# Check polled connections
|
||||
foreach my $connection ( @in_poll_connections )
|
||||
{
|
||||
my $messages = $connection->getMessages();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
# Check polled connections
|
||||
foreach my $connection ( @in_poll_connections )
|
||||
{
|
||||
my $messages = $connection->getMessages();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check for alarms that might have happened
|
||||
my @out_messages;
|
||||
foreach my $monitor ( values(%monitors) )
|
||||
{
|
||||
my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state", "shared_data:last_event" ] );
|
||||
# Check for alarms that might have happened
|
||||
my @out_messages;
|
||||
foreach my $monitor ( values(%monitors) )
|
||||
{
|
||||
my ( $state, $last_event )
|
||||
= zmMemRead( $monitor,
|
||||
[ "shared_data:state",
|
||||
"shared_data:last_event"
|
||||
]
|
||||
);
|
||||
|
||||
#print( "$monitor->{Id}: S:$state, LE:$last_event\n" );
|
||||
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" );
|
||||
if ( $state == STATE_ALARM || $state == STATE_ALERT ) # In alarm state
|
||||
{
|
||||
if ( !defined($monitor->{LastEvent}) || ($last_event != $monitor->{LastEvent}) ) # A new event
|
||||
{
|
||||
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
||||
}
|
||||
else # The same one as last time, so ignore it
|
||||
{
|
||||
# Do nothing
|
||||
}
|
||||
}
|
||||
elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) ) # Out of alarm state
|
||||
{
|
||||
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
||||
}
|
||||
elsif ( defined($monitor->{LastEvent}) && ($last_event != $monitor->{LastEvent}) ) # We've missed a whole event
|
||||
{
|
||||
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
||||
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
||||
}
|
||||
$monitor->{LastState} = $state;
|
||||
$monitor->{LastEvent} = $last_event;
|
||||
}
|
||||
foreach my $connection ( @out_connections )
|
||||
{
|
||||
if ( $connection->canWrite() )
|
||||
{
|
||||
$connection->putMessages( \@out_messages );
|
||||
}
|
||||
}
|
||||
foreach my $connection ( values(%spawned_connections) )
|
||||
{
|
||||
if ( $connection->canWrite() )
|
||||
{
|
||||
$connection->putMessages( \@out_messages );
|
||||
}
|
||||
}
|
||||
#print( "$monitor->{Id}: S:$state, LE:$last_event\n" );
|
||||
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" );
|
||||
if ( $state == STATE_ALARM
|
||||
|| $state == STATE_ALERT
|
||||
) # In alarm state
|
||||
{
|
||||
if ( !defined($monitor->{LastEvent})
|
||||
|| ($last_event != $monitor->{LastEvent})
|
||||
) # A new event
|
||||
{
|
||||
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
||||
}
|
||||
else # The same one as last time, so ignore it
|
||||
{
|
||||
# Do nothing
|
||||
}
|
||||
}
|
||||
elsif ( ($state == STATE_IDLE
|
||||
&& $monitor->{LastState} != STATE_IDLE
|
||||
)
|
||||
|| ($state == STATE_TAPE
|
||||
&& $monitor->{LastState} != STATE_TAPE
|
||||
)
|
||||
) # Out of alarm state
|
||||
{
|
||||
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
||||
}
|
||||
elsif ( defined($monitor->{LastEvent})
|
||||
&& ($last_event != $monitor->{LastEvent})
|
||||
) # We've missed a whole event
|
||||
{
|
||||
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
||||
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
||||
}
|
||||
$monitor->{LastState} = $state;
|
||||
$monitor->{LastEvent} = $last_event;
|
||||
}
|
||||
foreach my $connection ( @out_connections )
|
||||
{
|
||||
if ( $connection->canWrite() )
|
||||
{
|
||||
$connection->putMessages( \@out_messages );
|
||||
}
|
||||
}
|
||||
foreach my $connection ( values(%spawned_connections) )
|
||||
{
|
||||
if ( $connection->canWrite() )
|
||||
{
|
||||
$connection->putMessages( \@out_messages );
|
||||
}
|
||||
}
|
||||
|
||||
Debug( "Checking for timed actions\n" ) if ( int(keys(%actions)) );
|
||||
my $now = time();
|
||||
foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) )
|
||||
{
|
||||
Info( "Found actions expiring at $action_time\n" );
|
||||
foreach my $action ( @{$actions{$action_time}} )
|
||||
{
|
||||
my $connection = $action->{connection};
|
||||
my $message = $action->{message};
|
||||
Info( "Found action '$message'\n" );
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
delete( $actions{$action_time} );
|
||||
}
|
||||
Debug( "Checking for timed actions\n" )
|
||||
if ( int(keys(%actions)) );
|
||||
my $now = time();
|
||||
foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) )
|
||||
{
|
||||
Info( "Found actions expiring at $action_time\n" );
|
||||
foreach my $action ( @{$actions{$action_time}} )
|
||||
{
|
||||
my $connection = $action->{connection};
|
||||
my $message = $action->{message};
|
||||
Info( "Found action '$message'\n" );
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
delete( $actions{$action_time} );
|
||||
}
|
||||
|
||||
# Allow connections to do their own timed actions
|
||||
foreach my $connection ( @connections )
|
||||
{
|
||||
my $messages = $connection->timedActions();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach my $connection ( values(%spawned_connections) )
|
||||
{
|
||||
my $messages = $connection->timedActions();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach my $connection ( @connections )
|
||||
{
|
||||
my $messages = $connection->timedActions();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach my $connection ( values(%spawned_connections) )
|
||||
{
|
||||
my $messages = $connection->timedActions();
|
||||
if ( defined($messages) )
|
||||
{
|
||||
foreach my $message ( @$messages )
|
||||
{
|
||||
handleMessage( $connection, $message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If necessary reload monitors
|
||||
if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )
|
||||
{
|
||||
foreach my $monitor ( values(%monitors) )
|
||||
# If necessary reload monitors
|
||||
if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )
|
||||
{
|
||||
foreach my $monitor ( values(%monitors) )
|
||||
{
|
||||
# Free up any used memory handle
|
||||
zmMemInvalidate( $monitor );
|
||||
}
|
||||
loadMonitors();
|
||||
}
|
||||
loadMonitors();
|
||||
}
|
||||
}
|
||||
Info( "Trigger daemon exiting\n" );
|
||||
exit;
|
||||
|
||||
sub loadMonitors
|
||||
{
|
||||
Debug( "Loading monitors\n" );
|
||||
$monitor_reload_time = time();
|
||||
Debug( "Loading monitors\n" );
|
||||
$monitor_reload_time = time();
|
||||
|
||||
my %new_monitors = ();
|
||||
my %new_monitors = ();
|
||||
|
||||
my $sql = "select * from Monitors where find_in_set( Function, 'Modect,Mocord,Nodect' )";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok
|
||||
my $sql = "SELECT * FROM Monitors
|
||||
WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok
|
||||
|
||||
if ( defined($monitors{$monitor->{Id}}->{LastState}) )
|
||||
{
|
||||
$monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState};
|
||||
}
|
||||
else
|
||||
{
|
||||
$monitor->{LastState} = zmGetMonitorState( $monitor );
|
||||
}
|
||||
if ( defined($monitors{$monitor->{Id}}->{LastEvent}) )
|
||||
{
|
||||
$monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent};
|
||||
}
|
||||
else
|
||||
{
|
||||
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
|
||||
}
|
||||
$new_monitors{$monitor->{Id}} = $monitor;
|
||||
}
|
||||
%monitors = %new_monitors;
|
||||
if ( defined($monitors{$monitor->{Id}}->{LastState}) )
|
||||
{
|
||||
$monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState};
|
||||
}
|
||||
else
|
||||
{
|
||||
$monitor->{LastState} = zmGetMonitorState( $monitor );
|
||||
}
|
||||
if ( defined($monitors{$monitor->{Id}}->{LastEvent}) )
|
||||
{
|
||||
$monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent};
|
||||
}
|
||||
else
|
||||
{
|
||||
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
|
||||
}
|
||||
$new_monitors{$monitor->{Id}} = $monitor;
|
||||
}
|
||||
%monitors = %new_monitors;
|
||||
}
|
||||
|
||||
sub handleMessage
|
||||
{
|
||||
my $connection = shift;
|
||||
my $message = shift;
|
||||
my $connection = shift;
|
||||
my $message = shift;
|
||||
|
||||
my ( $id, $action, $score, $cause, $text, $showtext ) = split( /\|/, $message );
|
||||
$score = 0 if ( !defined($score) );
|
||||
$cause = "" if ( !defined($cause) );
|
||||
$text = "" if ( !defined($text) );
|
||||
my ( $id, $action, $score, $cause, $text, $showtext )
|
||||
= split( /\|/, $message );
|
||||
$score = 0 if ( !defined($score) );
|
||||
$cause = "" if ( !defined($cause) );
|
||||
$text = "" if ( !defined($text) );
|
||||
|
||||
my $monitor = $monitors{$id};
|
||||
if ( !$monitor )
|
||||
{
|
||||
Warning( "Can't find monitor '$id' for message '$message'\n" );
|
||||
return;
|
||||
}
|
||||
Debug( "Found monitor for id '$id'\n" );
|
||||
my $monitor = $monitors{$id};
|
||||
if ( !$monitor )
|
||||
{
|
||||
Warning( "Can't find monitor '$id' for message '$message'\n" );
|
||||
return;
|
||||
}
|
||||
Debug( "Found monitor for id '$id'\n" );
|
||||
|
||||
next if ( !zmMemVerify( $monitor ) );
|
||||
next if ( !zmMemVerify( $monitor ) );
|
||||
|
||||
Debug( "Handling action '$action'\n" );
|
||||
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ )
|
||||
{
|
||||
my $state = $1;
|
||||
my $delay = $2;
|
||||
if ( $state eq "enable" )
|
||||
{
|
||||
zmMonitorEnable( $monitor );
|
||||
}
|
||||
else
|
||||
{
|
||||
zmMonitorDisable( $monitor );
|
||||
}
|
||||
# Force a reload
|
||||
$monitor_reload_time = 0;
|
||||
Info( "Set monitor to $state\n" );
|
||||
if ( $delay )
|
||||
{
|
||||
my $action_time = time()+$delay;
|
||||
my $action_text = $id."|".(($state eq "enable")?"disable":"enable");
|
||||
my $action_array = $actions{$action_time};
|
||||
if ( !$action_array )
|
||||
{
|
||||
$action_array = $actions{$action_time} = [];
|
||||
}
|
||||
push( @$action_array, { connection=>$connection, message=>$action_text } );
|
||||
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
||||
}
|
||||
}
|
||||
elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ )
|
||||
{
|
||||
next if ( !$monitor->{Enabled} );
|
||||
Debug( "Handling action '$action'\n" );
|
||||
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ )
|
||||
{
|
||||
my $state = $1;
|
||||
my $delay = $2;
|
||||
if ( $state eq "enable" )
|
||||
{
|
||||
zmMonitorEnable( $monitor );
|
||||
}
|
||||
else
|
||||
{
|
||||
zmMonitorDisable( $monitor );
|
||||
}
|
||||
# Force a reload
|
||||
$monitor_reload_time = 0;
|
||||
Info( "Set monitor to $state\n" );
|
||||
if ( $delay )
|
||||
{
|
||||
my $action_time = time()+$delay;
|
||||
my $action_text = $id."|".( ($state eq "enable")
|
||||
? "disable"
|
||||
: "enable"
|
||||
)
|
||||
;
|
||||
my $action_array = $actions{$action_time};
|
||||
if ( !$action_array )
|
||||
{
|
||||
$action_array = $actions{$action_time} = [];
|
||||
}
|
||||
push( @$action_array, { connection=>$connection,
|
||||
message=>$action_text
|
||||
}
|
||||
);
|
||||
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
||||
}
|
||||
}
|
||||
elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ )
|
||||
{
|
||||
next if ( !$monitor->{Enabled} );
|
||||
|
||||
my $trigger = $1;
|
||||
my $delay = $2;
|
||||
my $trigger_data;
|
||||
if ( $trigger eq "on" )
|
||||
{
|
||||
zmTriggerEventOn( $monitor, $score, $cause, $text );
|
||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||
Info( "Trigger '$trigger' '$cause'\n" );
|
||||
}
|
||||
elsif ( $trigger eq "off" )
|
||||
{
|
||||
my $trigger = $1;
|
||||
my $delay = $2;
|
||||
my $trigger_data;
|
||||
if ( $trigger eq "on" )
|
||||
{
|
||||
zmTriggerEventOn( $monitor, $score, $cause, $text );
|
||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||
Info( "Trigger '$trigger' '$cause'\n" );
|
||||
}
|
||||
elsif ( $trigger eq "off" )
|
||||
{
|
||||
my $last_event = zmGetLastEvent( $monitor );
|
||||
zmTriggerEventOff( $monitor );
|
||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||
Info( "Trigger '$trigger'\n" );
|
||||
zmTriggerEventOff( $monitor );
|
||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||
Info( "Trigger '$trigger'\n" );
|
||||
# Wait til it's finished
|
||||
while( zmInAlarm( $monitor ) && ($last_event == zmGetLastEvent( $monitor )) )
|
||||
while( zmInAlarm( $monitor )
|
||||
&& ($last_event == zmGetLastEvent( $monitor ))
|
||||
)
|
||||
{
|
||||
# Tenth of a second
|
||||
usleep( 100000 );
|
||||
}
|
||||
zmTriggerEventCancel( $monitor );
|
||||
}
|
||||
else
|
||||
{
|
||||
Info( "Trigger '$trigger'\n" );
|
||||
zmTriggerEventCancel( $monitor );
|
||||
}
|
||||
if ( $delay )
|
||||
{
|
||||
my $action_time = time()+$delay;
|
||||
#my $action_text = $id."|cancel|0|".$cause."|".$text;
|
||||
my $action_text = $id."|cancel";
|
||||
my $action_array = $actions{$action_time};
|
||||
if ( !$action_array )
|
||||
{
|
||||
$action_array = $actions{$action_time} = [];
|
||||
}
|
||||
push( @$action_array, { connection=>$connection, message=>$action_text } );
|
||||
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
||||
}
|
||||
}
|
||||
elsif( $action eq "cancel" )
|
||||
{
|
||||
zmTriggerEventCancel( $monitor );
|
||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||
Info( "Cancelled event\n" );
|
||||
}
|
||||
elsif( $action eq "show" )
|
||||
{
|
||||
zmTriggerShowtext( $monitor, $showtext );
|
||||
Info( "Updated show text to '$showtext'\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Unrecognised action '$action' in message '$message'\n" );
|
||||
}
|
||||
zmTriggerEventCancel( $monitor );
|
||||
}
|
||||
else
|
||||
{
|
||||
Info( "Trigger '$trigger'\n" );
|
||||
zmTriggerEventCancel( $monitor );
|
||||
}
|
||||
if ( $delay )
|
||||
{
|
||||
my $action_time = time()+$delay;
|
||||
#my $action_text = $id."|cancel|0|".$cause."|".$text;
|
||||
my $action_text = $id."|cancel";
|
||||
my $action_array = $actions{$action_time};
|
||||
if ( !$action_array )
|
||||
{
|
||||
$action_array = $actions{$action_time} = [];
|
||||
}
|
||||
push( @$action_array, { connection=>$connection,
|
||||
message=>$action_text
|
||||
}
|
||||
);
|
||||
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
||||
}
|
||||
}
|
||||
elsif( $action eq "cancel" )
|
||||
{
|
||||
zmTriggerEventCancel( $monitor );
|
||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||
Info( "Cancelled event\n" );
|
||||
}
|
||||
elsif( $action eq "show" )
|
||||
{
|
||||
zmTriggerShowtext( $monitor, $showtext );
|
||||
Info( "Updated show text to '$showtext'\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Error( "Unrecognised action '$action' in message '$message'\n" );
|
||||
}
|
||||
} # end sub handleMessage
|
||||
|
||||
1;
|
||||
|
|
|
@ -20,11 +20,34 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# 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 NAME
|
||||
|
||||
zmupdate.pl - check and upgrade Zoneminer database
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmupdate.pl -c,--check | -f,--freshen | -v<version>,--version=<version> [-u<dbuser> -p<dbpass>]
|
||||
|
||||
=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
|
||||
|
||||
-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.
|
||||
-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
|
||||
-d<dir>,--dir=<dir> - Directory containing update files if not in default build location
|
||||
-interactive - interact with the user
|
||||
-nointeractive - do not interact with the user
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -52,7 +75,8 @@ use ZoneMinder::ConfigAdmin qw( :functions );
|
|||
use POSIX;
|
||||
use DBI;
|
||||
use Getopt::Long;
|
||||
use Data::Dumper;
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
|
||||
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
||||
|
||||
|
@ -78,27 +102,19 @@ my $version = '';
|
|||
my $dbUser = $Config{ZM_DB_USER};
|
||||
my $dbPass = $Config{ZM_DB_PASS};
|
||||
my $updateDir = '';
|
||||
sub Usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmupdate.pl <-c,--check|-f,--freshen|-v<version>,--version=<version>> [-u<dbuser> -p<dbpass>]>
|
||||
Parameters are :-
|
||||
-c, --check - Check for updated versions of ZoneMinder
|
||||
-f, --freshen - Freshen the configuration in the database. Equivalent of old zmconfig.pl -noi
|
||||
-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
|
||||
-d<dir>,--dir=<dir> - Directory containing update files if not in default build location
|
||||
-interactive - interact with the user
|
||||
-nointeractive - do not interact with the user
|
||||
");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
if ( !GetOptions( 'check'=>\$check, 'freshen'=>\$freshen, 'rename'=>\$rename, 'zone-fix'=>\$zoneFix, 'migrate-events'=>\$migrateEvents, 'version=s'=>\$version, 'interactive!'=>\$interactive, 'user:s'=>\$dbUser, 'pass:s'=>\$dbPass, 'dir:s'=>\$updateDir ) )
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
GetOptions(
|
||||
'check' =>\$check,
|
||||
'freshen' =>\$freshen,
|
||||
'rename' =>\$rename,
|
||||
'zone-fix' =>\$zoneFix,
|
||||
'migrate-events' =>\$migrateEvents,
|
||||
'version=s' =>\$version,
|
||||
'interactive!' =>\$interactive,
|
||||
'user:s' =>\$dbUser,
|
||||
'pass:s' =>\$dbPass,
|
||||
'dir:s' =>\$updateDir
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
$Config{ZM_DB_USER} = $dbUser;
|
||||
|
@ -113,14 +129,14 @@ if ( ! ($check || $freshen || $rename || $zoneFix || $migrateEvents || $version)
|
|||
else
|
||||
{
|
||||
print( STDERR "Please give a valid option\n" );
|
||||
Usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ($check + $freshen + $rename + $zoneFix + $migrateEvents + ($version?1:0)) > 1 )
|
||||
{
|
||||
print( STDERR "Please give only one option\n" );
|
||||
Usage();
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ( $check && $Config{ZM_CHECK_FOR_UPDATES} )
|
||||
|
|
|
@ -20,10 +20,37 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This script is used to create MPEG videos of events for the web pages
|
||||
# or as email attachments.
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmvideo.pl - ZoneMinder Video Creation Script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmvideo.pl -e <event_id>,--event=<event_id> [--format <format>]
|
||||
[--rate=<rate>]
|
||||
[--scale=<scale>]
|
||||
[--fps=<fps>]
|
||||
[--size=<size>]
|
||||
[--overwrite]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is used to create MPEG videos of events for the web pages
|
||||
or as email attachments.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
-e<event_id>, --event=<event_id> - What event to create the video for
|
||||
-f<format>, --format=<format> - What format to create the video in, default is mpg. For ffmpeg only.
|
||||
-r<rate>, --rate=<rate> - Relative rate, 1 = realtime, 2 = double speed, 0.5 = half speed etc.
|
||||
-s<scale>, --scale=<scale> - Scale, 1 = normal, 2 = double size, 0.5 = half size etc.
|
||||
-F<fps>, --fps=<fps> - Absolute frame rate, in frames per second
|
||||
-S<size>, --size=<size> - Absolute video size, WxH or other specification supported by ffmpeg
|
||||
-o, --overwrite - Whether to overwrite an existing file, off by default.
|
||||
-v, --version - Outputs the currently installed version of ZoneMinder
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -36,9 +63,10 @@ use bytes;
|
|||
@EXTRA_PERL_LIB@
|
||||
use ZoneMinder;
|
||||
use DBI;
|
||||
use Data::Dumper;
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
use POSIX qw(strftime);
|
||||
use Getopt::Long qw(:config no_ignore_case );
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
|
||||
$| = 1;
|
||||
|
||||
|
@ -60,77 +88,66 @@ my $version = 0;
|
|||
my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
|
||||
for ( my $i = 0; $i < @formats; $i++ )
|
||||
{
|
||||
if ( $i =~ /^(.+)\*$/ )
|
||||
{
|
||||
$format = $formats[$i] = $1;
|
||||
}
|
||||
if ( $i =~ /^(.+)\*$/ )
|
||||
{
|
||||
$format = $formats[$i] = $1;
|
||||
}
|
||||
}
|
||||
|
||||
sub Usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmvideo.pl -e <event_id>,--event=<event_id> [--format <format>] [--rate=<rate>] [--scale=<scale>] [--fps=<fps>] [--size=<size>] [--overwrite]
|
||||
Parameters are :-
|
||||
-e<event_id>, --event=<event_id> - What event to create the video for
|
||||
-f<format>, --format=<format> - What format to create the video in, default is mpg. For ffmpeg only.
|
||||
-r<rate>, --rate=<rate> - Relative rate , 1 = realtime, 2 = double speed , 0.5 = half speed etc
|
||||
-s<scale>, --scale=<scale> - Scale, 1 = normal, 2 = double size, 0.5 = half size etc
|
||||
-F<fps>, --fps=<fps> - Absolute frame rate, in frames per second
|
||||
-S<size>, --size=<size> - Absolute video size, WxH or other specification supported by ffmpeg
|
||||
-o, --overwrite - Whether to overwrite an existing file, off by default.
|
||||
-v, --version - Outputs the currently installed version of ZoneMinder
|
||||
");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
if ( !GetOptions( 'event=i'=>\$event_id, 'format|f=s'=>\$format, 'rate|r=f'=>\$rate, 'scale|s=f'=>\$scale, 'fps|F=f'=>\$fps, 'size|S=s'=>\$size, 'overwrite'=>\$overwrite, version=>\$version ) )
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
GetOptions(
|
||||
'event=i' =>\$event_id,
|
||||
'format|f=s' =>\$format,
|
||||
'rate|r=f' =>\$rate,
|
||||
'scale|s=f' =>\$scale,
|
||||
'fps|F=f' =>\$fps,
|
||||
'size|S=s' =>\$size,
|
||||
'overwrite' =>\$overwrite,
|
||||
'version' =>\$version
|
||||
) or pod2usage(-exitstatus => -1);
|
||||
|
||||
if ( $version ) {
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ( !$event_id || $event_id < 0 )
|
||||
{
|
||||
print( STDERR "Please give a valid event id\n" );
|
||||
Usage();
|
||||
print( STDERR "Please give a valid event id\n" );
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ( ! $Config{ZM_OPT_FFMPEG} )
|
||||
{
|
||||
print( STDERR "Mpeg encoding is not currently enabled\n" );
|
||||
exit(-1);
|
||||
print( STDERR "Mpeg encoding is not currently enabled\n" );
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ( !$rate && !$fps )
|
||||
{
|
||||
$rate = 1;
|
||||
$rate = 1;
|
||||
}
|
||||
|
||||
if ( !$scale && !$size )
|
||||
{
|
||||
$scale = 1;
|
||||
$scale = 1;
|
||||
}
|
||||
|
||||
if ( $rate && ($rate < 0.25 || $rate > 100) )
|
||||
{
|
||||
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
|
||||
Usage();
|
||||
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ( $scale && ($scale < 0.25 || $scale > 4) )
|
||||
{
|
||||
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
|
||||
Usage();
|
||||
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
if ( $fps && ($fps > 30) )
|
||||
{
|
||||
print( STDERR "FPS is out of range, <= 30\n" );
|
||||
Usage();
|
||||
print( STDERR "FPS is out of range, <= 30\n" );
|
||||
pod2usage(-exitstatus => -1);
|
||||
}
|
||||
|
||||
my ( $detaint_format ) = $format =~ /^(\w+)$/;
|
||||
|
@ -148,9 +165,23 @@ $size = $detaint_size;
|
|||
my $dbh = zmDbConnect();
|
||||
|
||||
my @filters;
|
||||
my $sql = "select max(F.Delta)-min(F.Delta) as FullLength, E.*, unix_timestamp(E.StartTime) as Time, M.Name as MonitorName, M.Width as MonitorWidth, M.Height as MonitorHeight, M.Palette from Frames as F inner join Events as E on F.EventId = E.Id inner join Monitors as M on E.MonitorId = M.Id where EventId = '$event_id' group by F.EventId";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength,
|
||||
E.*,
|
||||
unix_timestamp(E.StartTime) as Time,
|
||||
M.Name as MonitorName,
|
||||
M.Width as MonitorWidth,
|
||||
M.Height as MonitorHeight,
|
||||
M.Palette
|
||||
FROM Frames as F
|
||||
INNER JOIN Events as E on F.EventId = E.Id
|
||||
INNER JOIN Monitors as M on E.MonitorId = M.Id
|
||||
WHERE EventId = '$event_id'
|
||||
GROUP BY F.EventId"
|
||||
;
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
my $event = $sth->fetchrow_hashref();
|
||||
$sth->finish();
|
||||
my $event_path = getEventPath( $event );
|
||||
|
@ -160,42 +191,42 @@ chdir( $event_path );
|
|||
my @file_parts;
|
||||
if ( $rate )
|
||||
{
|
||||
my $file_rate = $rate;
|
||||
$file_rate =~ s/\./_/;
|
||||
$file_rate =~ s/_00//;
|
||||
$file_rate =~ s/(_\d+)0+$/$1/;
|
||||
$file_rate = 'r'.$file_rate;
|
||||
push( @file_parts, $file_rate );
|
||||
my $file_rate = $rate;
|
||||
$file_rate =~ s/\./_/;
|
||||
$file_rate =~ s/_00//;
|
||||
$file_rate =~ s/(_\d+)0+$/$1/;
|
||||
$file_rate = 'r'.$file_rate;
|
||||
push( @file_parts, $file_rate );
|
||||
}
|
||||
elsif ( $fps )
|
||||
{
|
||||
my $file_fps = $fps;
|
||||
$file_fps =~ s/\./_/;
|
||||
$file_fps =~ s/_00//;
|
||||
$file_fps =~ s/(_\d+)0+$/$1/;
|
||||
$file_fps = 'R'.$file_fps;
|
||||
push( @file_parts, $file_fps );
|
||||
my $file_fps = $fps;
|
||||
$file_fps =~ s/\./_/;
|
||||
$file_fps =~ s/_00//;
|
||||
$file_fps =~ s/(_\d+)0+$/$1/;
|
||||
$file_fps = 'R'.$file_fps;
|
||||
push( @file_parts, $file_fps );
|
||||
}
|
||||
|
||||
if ( $scale )
|
||||
{
|
||||
my $file_scale = $scale;
|
||||
$file_scale =~ s/\./_/;
|
||||
$file_scale =~ s/_00//;
|
||||
$file_scale =~ s/(_\d+)0+$/$1/;
|
||||
$file_scale = 's'.$file_scale;
|
||||
push( @file_parts, $file_scale );
|
||||
my $file_scale = $scale;
|
||||
$file_scale =~ s/\./_/;
|
||||
$file_scale =~ s/_00//;
|
||||
$file_scale =~ s/(_\d+)0+$/$1/;
|
||||
$file_scale = 's'.$file_scale;
|
||||
push( @file_parts, $file_scale );
|
||||
}
|
||||
elsif ( $size )
|
||||
{
|
||||
my $file_size = 'S'.$size;
|
||||
push( @file_parts, $file_size );
|
||||
my $file_size = 'S'.$size;
|
||||
push( @file_parts, $file_size );
|
||||
}
|
||||
my $video_file = "$video_name-".$file_parts[0]."-".$file_parts[1].".$format";
|
||||
|
||||
if ( $overwrite || !-s $video_file )
|
||||
{
|
||||
Info( "Creating video file $video_file for event $event->{Id}\n" );
|
||||
Info( "Creating video file $video_file for event $event->{Id}\n" );
|
||||
|
||||
my $frame_rate = sprintf( "%.2f", $event->{Frames}/$event->{FullLength} );
|
||||
if ( $rate )
|
||||
|
@ -228,22 +259,32 @@ if ( $overwrite || !-s $video_file )
|
|||
$video_size = $size;
|
||||
}
|
||||
|
||||
my $command = $Config{ZM_PATH_FFMPEG}." -y -r $frame_rate ".$Config{ZM_FFMPEG_INPUT_OPTIONS}." -i %0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg -s $video_size ".$Config{ZM_FFMPEG_OUTPUT_OPTIONS}." '$video_file' > ffmpeg.log 2>&1";
|
||||
my $command = $Config{ZM_PATH_FFMPEG}
|
||||
." -y -r $frame_rate "
|
||||
.$Config{ZM_FFMPEG_INPUT_OPTIONS}
|
||||
." -i %0"
|
||||
.$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||
."d-capture.jpg -s $video_size "
|
||||
.$Config{ZM_FFMPEG_OUTPUT_OPTIONS}
|
||||
." '$video_file' > ffmpeg.log 2>&1"
|
||||
;
|
||||
Debug( $command."\n" );
|
||||
my $output = qx($command);
|
||||
|
||||
my $status = $? >> 8;
|
||||
if ( $status )
|
||||
{
|
||||
Error( "Unable to generate video, check ".$event_path."/ffmpeg.log for details" );
|
||||
Error( "Unable to generate video, check "
|
||||
.$event_path."/ffmpeg.log for details"
|
||||
);
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
Info( "Finished $video_file\n" );
|
||||
|
||||
Info( "Finished $video_file\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Info( "Video file $video_file already exists for event $event->{Id}\n" );
|
||||
Info( "Video file $video_file already exists for event $event->{Id}\n" );
|
||||
}
|
||||
#print( STDOUT $event->{MonitorId}.'/'.$event->{Id}.'/'.$video_file."\n" );
|
||||
print( STDOUT $event_path . '/' . $video_file ."\n" );
|
||||
|
|
|
@ -20,11 +20,22 @@
|
|||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This does some basic setup for ZoneMinder to run and then periodically
|
||||
# checks the fps output of the active daemons to check they haven't
|
||||
# locked up. If they have then they are killed and restarted
|
||||
#
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmwatch.pl - ZoneMinder WatchDog Script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmwatch.pl
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This does some basic setup for ZoneMinder to run and then periodically
|
||||
checks the fps output of the active daemons to check they haven't
|
||||
locked up. If they have then they are killed and restarted
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
|
@ -46,7 +57,7 @@ use constant START_DELAY => 30; # To give everything else time to start
|
|||
use ZoneMinder;
|
||||
use POSIX;
|
||||
use DBI;
|
||||
use Data::Dumper;
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
|
||||
$| = 1;
|
||||
|
||||
|
@ -54,14 +65,6 @@ $ENV{PATH} = '/bin:/usr/bin';
|
|||
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
|
||||
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||
|
||||
sub Usage
|
||||
{
|
||||
print( "
|
||||
Usage: zmwatch.pl
|
||||
");
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
logInit();
|
||||
logSetSignal();
|
||||
|
||||
|
@ -72,38 +75,49 @@ sleep( START_DELAY );
|
|||
my $dbh = zmDbConnect();
|
||||
|
||||
my $sql = "select * from Monitors";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
my $now = time();
|
||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
if ( $monitor->{Function} ne 'None' )
|
||||
{
|
||||
my $now = time();
|
||||
my $res = $sth->execute()
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() )
|
||||
{
|
||||
if ( $monitor->{Function} ne 'None' )
|
||||
{
|
||||
my $restart = 0;
|
||||
if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) )
|
||||
{
|
||||
# Check we have got an image recently
|
||||
my $image_time = zmGetLastWriteTime( $monitor );
|
||||
next if ( !defined($image_time) ); # Can't read from shared data
|
||||
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
|
||||
if ( zmMemVerify( $monitor )
|
||||
&& zmMemRead( $monitor, "shared_data:valid" )
|
||||
)
|
||||
{
|
||||
# Check we have got an image recently
|
||||
my $image_time = zmGetLastWriteTime( $monitor );
|
||||
next if ( !defined($image_time) ); # Can't read from shared data
|
||||
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
|
||||
|
||||
my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY};
|
||||
my $image_delay = $now-$image_time;
|
||||
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
|
||||
if ( $image_delay > $max_image_delay )
|
||||
{
|
||||
Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" );
|
||||
my $max_image_delay = ( $monitor->{MaxFPS}
|
||||
&&($monitor->{MaxFPS}>0)
|
||||
&&($monitor->{MaxFPS}<1)
|
||||
) ? (3/$monitor->{MaxFPS})
|
||||
: $Config{ZM_WATCH_MAX_DELAY}
|
||||
;
|
||||
my $image_delay = $now-$image_time;
|
||||
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
|
||||
if ( $image_delay > $max_image_delay )
|
||||
{
|
||||
Info( "Restarting capture daemon for "
|
||||
.$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n"
|
||||
);
|
||||
$restart = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
#Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" );
|
||||
#$restart = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $restart )
|
||||
{
|
||||
|
@ -120,19 +134,28 @@ while( 1 )
|
|||
}
|
||||
elsif ( $monitor->{Function} ne 'Monitor' )
|
||||
{
|
||||
if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) )
|
||||
if ( zmMemVerify( $monitor )
|
||||
&& zmMemRead( $monitor, "shared_data:valid" )
|
||||
)
|
||||
{
|
||||
# Check we have got an image recently
|
||||
my $image_time = zmGetLastReadTime( $monitor );
|
||||
next if ( !defined($image_time) ); # Can't read from shared data
|
||||
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
|
||||
|
||||
my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY};
|
||||
my $max_image_delay = ( $monitor->{MaxFPS}
|
||||
&&($monitor->{MaxFPS}>0)
|
||||
&&($monitor->{MaxFPS}<1)
|
||||
) ? (3/$monitor->{MaxFPS})
|
||||
: $Config{ZM_WATCH_MAX_DELAY}
|
||||
;
|
||||
my $image_delay = $now-$image_time;
|
||||
Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" );
|
||||
if ( $image_delay > $max_image_delay )
|
||||
{
|
||||
Info( "Restarting analysis daemon for ".$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n" );
|
||||
Info( "Restarting analysis daemon for "
|
||||
.$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n"
|
||||
);
|
||||
my $command = "zmdc.pl restart zma -m ".$monitor->{Id};
|
||||
runCommand( $command );
|
||||
}
|
||||
|
@ -141,8 +164,8 @@ while( 1 )
|
|||
}
|
||||
# Prevent open handles building up if we have connect to shared memory
|
||||
zmMemInvalidate( $monitor );
|
||||
}
|
||||
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
|
||||
}
|
||||
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
|
||||
}
|
||||
Info( "Watchdog exiting\n" );
|
||||
exit();
|
||||
|
|
1105
scripts/zmx10.pl.in
1105
scripts/zmx10.pl.in
File diff suppressed because it is too large
Load Diff
|
@ -14,7 +14,6 @@ add_executable(zma zma.cpp)
|
|||
add_executable(zmu zmu.cpp)
|
||||
add_executable(zmf zmf.cpp)
|
||||
add_executable(zms zms.cpp)
|
||||
add_executable(nph-zms zms.cpp)
|
||||
add_executable(zmstreamer zmstreamer.cpp)
|
||||
|
||||
target_link_libraries(zmc zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
|
@ -22,10 +21,9 @@ target_link_libraries(zma zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
|||
target_link_libraries(zmu zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zmf zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(nph-zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
target_link_libraries(zmstreamer zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS})
|
||||
|
||||
install(TARGETS zmc zma zmu zmf zmstreamer RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(TARGETS zms nph-zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
install(TARGETS zms RUNTIME DESTINATION "${ZM_CGIDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(CODE "execute_process(COMMAND ln -sf zms nph-zms WORKING_DIRECTORY \"\$ENV{DESTDIR}${ZM_CGIDIR}\")")
|
||||
|
||||
|
|
10
src/zm.h
10
src/zm.h
|
@ -17,14 +17,24 @@
|
|||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
//
|
||||
|
||||
#if !defined(PATH_MAX)
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
#ifndef ZM_H
|
||||
#define ZM_H
|
||||
|
||||
#include "zm_config.h"
|
||||
#ifdef SOLARIS
|
||||
#undef DEFAULT_TYPE // pthread defines this which breaks StreamType DEFAULT_TYPE
|
||||
#include <string.h> // define strerror() and friends
|
||||
#endif
|
||||
#include "zm_logger.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
extern const char* self;
|
||||
|
||||
#endif // ZM_H
|
||||
|
|
|
@ -23,7 +23,11 @@
|
|||
#include "zm.h"
|
||||
#include "zm_coord.h"
|
||||
|
||||
#ifndef SOLARIS
|
||||
#include <math.h>
|
||||
#else
|
||||
#include <cmath>
|
||||
#endif
|
||||
|
||||
//
|
||||
// Class used for storing a box, which is defined as a region
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#include <sys/param.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#ifdef SOLARIS
|
||||
#include <sys/filio.h> // define FIONREAD
|
||||
#endif
|
||||
|
||||
int CommsBase::readV( int iovcnt, /* const void *, int, */ ... )
|
||||
{
|
||||
va_list arg_ptr;
|
||||
|
|
|
@ -36,6 +36,12 @@
|
|||
#include "zm_event.h"
|
||||
#include "zm_monitor.h"
|
||||
|
||||
// sendfile tricks
|
||||
extern "C"
|
||||
{
|
||||
#include "zm_sendfile.h"
|
||||
}
|
||||
|
||||
#include "zmf.h"
|
||||
|
||||
#if HAVE_SYS_SENDFILE_H
|
||||
|
@ -1431,7 +1437,7 @@ bool EventStream::sendFrame( int delta_us )
|
|||
if(send_raw) {
|
||||
#if HAVE_SENDFILE
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size );
|
||||
if(sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) {
|
||||
if(zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size) {
|
||||
/* sendfile() failed, use standard way instead */
|
||||
img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj );
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) {
|
||||
|
@ -1544,8 +1550,10 @@ void EventStream::runStream()
|
|||
if ( ((curr_frame_id-1)%frame_mod) == 0 )
|
||||
{
|
||||
delta_us = (unsigned int)(frame_data->delta * 1000000);
|
||||
if ( effective_fps < base_fps )
|
||||
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
|
||||
// if effective > base we should speed up frame delivery
|
||||
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
|
||||
// but must not exceed maxfps
|
||||
delta_us = max(delta_us, 1000000 / maxfps);
|
||||
send_frame = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,13 +86,21 @@ SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL),
|
|||
Debug(4,"SWScale object created");
|
||||
|
||||
/* Allocate AVFrame for the input */
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
input_avframe = av_frame_alloc();
|
||||
#else
|
||||
input_avframe = avcodec_alloc_frame();
|
||||
#endif
|
||||
if(input_avframe == NULL) {
|
||||
Fatal("Failed allocating AVFrame for the input");
|
||||
}
|
||||
|
||||
/* Allocate AVFrame for the output */
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
output_avframe = av_frame_alloc();
|
||||
#else
|
||||
output_avframe = avcodec_alloc_frame();
|
||||
#endif
|
||||
if(output_avframe == NULL) {
|
||||
Fatal("Failed allocating AVFrame for the output");
|
||||
}
|
||||
|
@ -140,7 +148,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
|
|||
return -3;
|
||||
}
|
||||
|
||||
#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 8, 0)
|
||||
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
|
||||
/* Warn if the input or output pixelformat is not supported */
|
||||
if(!sws_isSupportedInput(in_pf)) {
|
||||
Warning("swscale does not support the input format: %c%c%c%c",(in_pf)&0xff,((in_pf)&0xff),((in_pf>>16)&0xff),((in_pf>>24)&0xff));
|
||||
|
|
|
@ -32,7 +32,17 @@ extern "C" {
|
|||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/base64.h>
|
||||
#include <libavutil/mathematics.h>
|
||||
#if LIBAVUTIL_VERSION_INT > AV_VERSION_INT(50, 28, 0)
|
||||
|
||||
/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVUTIL_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVUTIL_VERSION_MICRO < 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVUTIL_VERSION_MICRO >= 100 && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(50, 29, 0, 29, 0)
|
||||
#include <libavutil/opt.h>
|
||||
#else
|
||||
#include <libavcodec/opt.h>
|
||||
|
@ -42,43 +52,82 @@ extern "C" {
|
|||
#include <ffmpeg/base64.h>
|
||||
#include <ffmpeg/mathematics.h>
|
||||
#include <ffmpeg/opt.h>
|
||||
#endif
|
||||
#endif /* HAVE_LIBAVUTIL_AVUTIL_H */
|
||||
|
||||
// AVCODEC
|
||||
#if HAVE_LIBAVCODEC_AVCODEC_H
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
/*
|
||||
* LIBAVCODEC_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVCODEC_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVCODEC_VERSION_MICRO < 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_AVCODEC_H
|
||||
#include <ffmpeg/avcodec.h>
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_LIBAVCODEC_AVCODEC_H */
|
||||
|
||||
#if defined(HAVE_LIBAVCODEC_AVCODEC_H)
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,25,0)
|
||||
#if LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100)
|
||||
#define _AVCODECID AVCodecID
|
||||
#else
|
||||
#define _AVCODECID CodecID
|
||||
#endif
|
||||
#endif
|
||||
#endif /* HAVE_LIBAVCODEC_AVCODEC_H */
|
||||
|
||||
// AVFORMAT
|
||||
#if HAVE_LIBAVFORMAT_AVFORMAT_H
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
/* LIBAVFORMAT_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVFORMAT_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVFORMAT_VERSION_MICRO < 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVFORMAT_VERSION_MICRO >= 100 && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_AVFORMAT_H
|
||||
#include <ffmpeg/avformat.h>
|
||||
#endif
|
||||
#endif /* HAVE_LIBAVFORMAT_AVFORMAT_H */
|
||||
|
||||
// AVDEVICE
|
||||
#if HAVE_LIBAVDEVICE_AVDEVICE_H
|
||||
#include <libavdevice/avdevice.h>
|
||||
|
||||
/* LIBAVDEVICE_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBAVDEVICE_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBAVDEVICE_VERSION_MICRO < 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBAVDEVICE_VERSION_MICRO >= 100 && LIBAVDEVICE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_AVDEVICE_H
|
||||
#include <ffmpeg/avdevice.h>
|
||||
#endif
|
||||
#endif /* HAVE_LIBAVDEVICE_AVDEVICE_H */
|
||||
|
||||
// SWSCALE
|
||||
#if HAVE_LIBSWSCALE_SWSCALE_H
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
/* LIBSWSCALE_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||
* a is the major version
|
||||
* b and c the minor and micro versions of libav
|
||||
* d and e the minor and micro versions of FFmpeg */
|
||||
#define LIBSWSCALE_VERSION_CHECK(a, b, c, d, e) \
|
||||
( (LIBSWSCALE_VERSION_MICRO < 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, b, c) ) || \
|
||||
(LIBSWSCALE_VERSION_MICRO >= 100 && LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(a, d, e) ) )
|
||||
|
||||
#elif HAVE_FFMPEG_SWSCALE_H
|
||||
#include <ffmpeg/swscale.h>
|
||||
#endif
|
||||
#endif /* HAVE_LIBSWSCALE_SWSCALE_H */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -86,7 +135,7 @@ extern "C" {
|
|||
|
||||
#if ( HAVE_LIBAVUTIL_AVUTIL_H || HAVE_LIBAVCODEC_AVCODEC_H || HAVE_LIBAVFORMAT_AVFORMAT_H || HAVE_LIBAVDEVICE_AVDEVICE_H )
|
||||
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(52, 107, 0, 107, 0)
|
||||
#if defined(AVIO_WRONLY)
|
||||
#define AVIO_FLAG_WRITE AVIO_WRONLY
|
||||
#else
|
||||
|
@ -131,7 +180,7 @@ protected:
|
|||
};
|
||||
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 25, 0)
|
||||
#if !LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100)
|
||||
#define AV_CODEC_ID_NONE CODEC_ID_NONE
|
||||
#define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW
|
||||
#define AV_CODEC_ID_PCM_ALAW CODEC_ID_PCM_ALAW
|
||||
|
@ -167,18 +216,18 @@ protected:
|
|||
inline static const std::string av_make_error_string(int errnum)
|
||||
{
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE];
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(50, 12, 13)
|
||||
#if LIBAVUTIL_VERSION_CHECK(50, 13, 0, 13, 0)
|
||||
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
|
||||
#else
|
||||
snprintf(errbuf, AV_ERROR_MAX_STRING_SIZE, "libav error %d", errnum);
|
||||
#endif
|
||||
return (std::string)errbuf;
|
||||
}
|
||||
|
||||
|
||||
#undef av_err2str
|
||||
#define av_err2str(errnum) av_make_error_string(errnum).c_str()
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
#endif // ( HAVE_LIBAVUTIL_AVUTIL_H || HAVE_LIBAVCODEC_AVCODEC_H || HAVE_LIBAVFORMAT_AVFORMAT_H || HAVE_LIBAVDEVICE_AVDEVICE_H )
|
||||
|
|
|
@ -30,6 +30,12 @@ extern "C"{
|
|||
#define AV_ERROR_MAX_STRING_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifdef SOLARIS
|
||||
#include <sys/errno.h> // for ESRCH
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture ) :
|
||||
Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture ),
|
||||
mPath( p_path ),
|
||||
|
@ -128,7 +134,7 @@ int FfmpegCamera::Capture( Image &image )
|
|||
void *retval = 0;
|
||||
int ret;
|
||||
|
||||
ret = pthread_tryjoin_np(mReopenThread, &retval);
|
||||
ret = pthread_join(mReopenThread, &retval);
|
||||
if (ret != 0){
|
||||
Error("Could not join reopen thread.");
|
||||
}
|
||||
|
@ -172,7 +178,7 @@ int FfmpegCamera::Capture( Image &image )
|
|||
Debug( 5, "Got packet from stream %d", packet.stream_index );
|
||||
if ( packet.stream_index == mVideoStreamId )
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0)
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 )
|
||||
#else
|
||||
if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 )
|
||||
|
@ -226,7 +232,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
mIsOpening = true;
|
||||
|
||||
// Open the input, not necessarily a file
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0)
|
||||
Debug ( 1, "Calling av_open_input_file" );
|
||||
if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) !=0 )
|
||||
#else
|
||||
|
@ -283,7 +289,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
//mFormatContext->probesize = 32;
|
||||
//mFormatContext->max_analyze_duration = 32;
|
||||
// Locate stream info from avformat_open_input
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0)
|
||||
Debug ( 1, "Calling av_find_stream_info" );
|
||||
if ( av_find_stream_info( mFormatContext ) < 0 )
|
||||
#else
|
||||
|
@ -291,15 +297,14 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
if ( avformat_find_stream_info( mFormatContext, 0 ) < 0 )
|
||||
#endif
|
||||
Fatal( "Unable to find stream info from %s due to: %s", mPath.c_str(), strerror(errno) );
|
||||
|
||||
Info( "Find stream info complete %s", mPath.c_str() );
|
||||
|
||||
Debug ( 1, "Got stream info" );
|
||||
|
||||
// Find first video stream present
|
||||
mVideoStreamId = -1;
|
||||
for (unsigned int i=0; i < mFormatContext->nb_streams; i++ )
|
||||
{
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1)
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
|
||||
|
@ -310,7 +315,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
}
|
||||
if(mAudioStreamId == -1) //FIXME best way to copy all other streams?
|
||||
{
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(51,2,1)
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO )
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO )
|
||||
|
@ -334,7 +339,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Debug ( 1, "Found decoder" );
|
||||
|
||||
// Open the codec
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 7, 0)
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
|
||||
Debug ( 1, "Calling avcodec_open" );
|
||||
if ( avcodec_open( mCodecContext, mCodec ) < 0 )
|
||||
#else
|
||||
|
@ -346,11 +351,19 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Debug ( 1, "Opened codec" );
|
||||
|
||||
// Allocate space for the native video frame
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
mRawFrame = av_frame_alloc();
|
||||
#else
|
||||
mRawFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
|
||||
// Allocate space for the converted video frame
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
mFrame = av_frame_alloc();
|
||||
#else
|
||||
mFrame = avcodec_alloc_frame();
|
||||
|
||||
#endif
|
||||
|
||||
if(mRawFrame == NULL || mFrame == NULL)
|
||||
Fatal( "Unable to allocate frame for %s", mPath.c_str() );
|
||||
|
||||
|
@ -377,11 +390,9 @@ int FfmpegCamera::OpenFfmpeg() {
|
|||
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
|
||||
Info( "Primed capture from %s, video=%d, audio=%d", mPath.c_str(), mVideoStreamId, mAudioStreamId);
|
||||
mCanCapture = true;
|
||||
|
||||
mCanCapture = true;
|
||||
|
||||
return( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FfmpegCamera::ReopenFfmpeg() {
|
||||
|
@ -421,7 +432,7 @@ int FfmpegCamera::CloseFfmpeg(){
|
|||
}
|
||||
if ( mFormatContext )
|
||||
{
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 4, 0)
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0)
|
||||
av_close_input_file( mFormatContext );
|
||||
#else
|
||||
avformat_close_input( &mFormatContext );
|
||||
|
@ -455,7 +466,7 @@ void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){
|
|||
// Close current stream.
|
||||
camera->CloseFfmpeg();
|
||||
|
||||
// Sleep if neccessary to not reconnect too fast.
|
||||
// Sleep if necessary to not reconnect too fast.
|
||||
int wait = config.ffmpeg_open_timeout - (time(NULL) - camera->mOpenStart);
|
||||
wait = wait < 0 ? 0 : wait;
|
||||
if (wait > 0){
|
||||
|
@ -481,7 +492,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
|||
void *retval = 0;
|
||||
int ret;
|
||||
|
||||
ret = pthread_tryjoin_np(mReopenThread, &retval);
|
||||
ret = pthread_join(mReopenThread, &retval);
|
||||
if (ret != 0){
|
||||
Error("Could not join reopen thread.");
|
||||
}
|
||||
|
@ -525,7 +536,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
|||
Debug( 5, "Got packet from stream %d", packet.stream_index );
|
||||
if ( packet.stream_index == mVideoStreamId )
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0)
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 )
|
||||
#else
|
||||
if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 )
|
||||
|
|
|
@ -104,13 +104,13 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin
|
|||
pixels = width*height;
|
||||
colours = p_colours;
|
||||
subpixelorder = p_subpixelorder;
|
||||
size = (width*height)*colours;
|
||||
size = pixels*colours;
|
||||
buffer = 0;
|
||||
holdbuffer = 0;
|
||||
if ( p_buffer )
|
||||
{
|
||||
allocation = size;
|
||||
buffertype = ZM_BUFTYPE_DONTFREE;
|
||||
allocation = size;
|
||||
buffertype = ZM_BUFTYPE_DONTFREE;
|
||||
buffer = p_buffer;
|
||||
}
|
||||
else
|
||||
|
@ -129,10 +129,10 @@ Image::Image( const Image &p_image )
|
|||
pixels = p_image.pixels;
|
||||
colours = p_image.colours;
|
||||
subpixelorder = p_image.subpixelorder;
|
||||
size = allocation = p_image.size;
|
||||
size = p_image.size; // allocation is set in AllocImgBuffer
|
||||
buffer = 0;
|
||||
holdbuffer = 0;
|
||||
AllocImgBuffer(allocation);
|
||||
AllocImgBuffer(size);
|
||||
(*fptr_imgbufcpy)(buffer, p_image.buffer, size);
|
||||
strncpy( text, p_image.text, sizeof(text) );
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ void Image::Initialise()
|
|||
initialised = true;
|
||||
}
|
||||
|
||||
/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can gurantee that a buffer of required size exists */
|
||||
/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can guarantee that a buffer of required size exists */
|
||||
uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) {
|
||||
unsigned int newsize;
|
||||
|
||||
|
@ -331,7 +331,7 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
|
|||
return NULL;
|
||||
} else {
|
||||
/* Replace buffer with a bigger one */
|
||||
DumpImgBuffer();
|
||||
//DumpImgBuffer(); // Done in AllocImgBuffer too
|
||||
AllocImgBuffer(newsize);
|
||||
}
|
||||
}
|
||||
|
@ -369,12 +369,12 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh
|
|||
unsigned int new_buffer_size = ((p_width*p_height)*p_colours);
|
||||
|
||||
if(buffer_size < new_buffer_size) {
|
||||
Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours );
|
||||
Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours, new_buffer_size );
|
||||
return;
|
||||
}
|
||||
|
||||
if(holdbuffer && buffer) {
|
||||
if((unsigned int)((p_height*p_width)*p_colours) > allocation) {
|
||||
if(new_buffer_size > allocation) {
|
||||
Error("Held buffer is undersized for assigned buffer");
|
||||
return;
|
||||
} else {
|
||||
|
@ -482,7 +482,7 @@ void Image::Assign( const Image &image ) {
|
|||
}
|
||||
} else {
|
||||
if(new_size > allocation || !buffer) {
|
||||
DumpImgBuffer();
|
||||
// DumpImgBuffer(); This is also done in AllocImgBuffer
|
||||
AllocImgBuffer(new_size);
|
||||
}
|
||||
}
|
||||
|
@ -1580,7 +1580,11 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres
|
|||
{
|
||||
uint8_t *psrc = images[j]->buffer+c;
|
||||
|
||||
#ifndef SOLARIS
|
||||
if ( (unsigned)abs((*psrc)-RGB_VAL(ref_colour,c)) >= RGB_VAL(threshold,c) )
|
||||
#else
|
||||
if ( (unsigned)std::abs((*psrc)-RGB_VAL(ref_colour,c)) >= RGB_VAL(threshold,c) )
|
||||
#endif
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
@ -1593,7 +1597,7 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres
|
|||
return( result );
|
||||
}
|
||||
|
||||
/* New function to allow buffer re-using instead of allocationg memory for the delta image everytime */
|
||||
/* New function to allow buffer re-using instead of allocationg memory for the delta image every time */
|
||||
void Image::Delta( const Image &image, Image* targetimage) const
|
||||
{
|
||||
#ifdef ZM_IMAGE_PROFILING
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <list>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "zm.h"
|
||||
|
|
|
@ -32,6 +32,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Workaround for GNU/kFreeBSD */
|
||||
#if defined(__FreeBSD_kernel__)
|
||||
#ifndef ENODATA
|
||||
#define ENODATA ENOATTR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static unsigned int BigEndian;
|
||||
|
||||
static int vidioctl( int fd, int request, void *arg )
|
||||
|
@ -255,7 +262,7 @@ static PixelFormat getFfPixFormatFromV4lPalette( int v4l_version, int palette )
|
|||
|
||||
#if ZM_HAS_V4L2
|
||||
static char palette_desc[32];
|
||||
/* Automatic format selection prefered formats */
|
||||
/* Automatic format selection preferred formats */
|
||||
static const uint32_t prefered_rgb32_formats[] = {V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
||||
static const uint32_t prefered_rgb24_formats[] = {V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
||||
static const uint32_t prefered_gray8_formats[] = {V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420};
|
||||
|
@ -427,7 +434,7 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel,
|
|||
Panic("Unexpected colours: %d",colours);
|
||||
}
|
||||
if( capture ) {
|
||||
#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0, 8, 0)
|
||||
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
|
||||
if(!sws_isSupportedInput(capturePixFormat)) {
|
||||
Error("swscale does not support the used capture format: %c%c%c%c",(capturePixFormat)&0xff,((capturePixFormat>>8)&0xff),((capturePixFormat>>16)&0xff),((capturePixFormat>>24)&0xff));
|
||||
conversion_type = 2; /* Try ZM format conversions */
|
||||
|
@ -615,7 +622,11 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel,
|
|||
#if HAVE_LIBSWSCALE
|
||||
/* Initialize swscale stuff */
|
||||
if(capture && conversion_type == 1) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
tmpPicture = av_frame_alloc();
|
||||
#else
|
||||
tmpPicture = avcodec_alloc_frame();
|
||||
#endif
|
||||
if ( !tmpPicture )
|
||||
Fatal( "Could not allocate temporary picture" );
|
||||
|
||||
|
@ -845,7 +856,11 @@ void LocalCamera::Initialise()
|
|||
Fatal( "Can't map video buffer %d (%d bytes) to memory: %s(%d)", i, vid_buf.length, strerror(errno), errno );
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
capturePictures[i] = av_frame_alloc();
|
||||
#else
|
||||
capturePictures[i] = avcodec_alloc_frame();
|
||||
#endif
|
||||
if ( !capturePictures[i] )
|
||||
Fatal( "Could not allocate picture" );
|
||||
avpicture_fill( (AVPicture *)capturePictures[i], (uint8_t*)v4l2_data.buffers[i].start, capturePixFormat, v4l2_data.fmt.fmt.pix.width, v4l2_data.fmt.fmt.pix.height );
|
||||
|
@ -999,7 +1014,11 @@ void LocalCamera::Initialise()
|
|||
v4l1_data.buffers[i].height = height;
|
||||
v4l1_data.buffers[i].format = palette;
|
||||
|
||||
#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101)
|
||||
capturePictures[i] = av_frame_alloc();
|
||||
#else
|
||||
capturePictures[i] = avcodec_alloc_frame();
|
||||
#endif
|
||||
if ( !capturePictures[i] )
|
||||
Fatal( "Could not allocate picture" );
|
||||
avpicture_fill( (AVPicture *)capturePictures[i], (unsigned char *)v4l1_data.bufptr+v4l1_data.frames.offsets[i], capturePixFormat, width, height );
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#ifdef HAVE_LINUX_VIDEODEV_H
|
||||
#include <linux/videodev.h>
|
||||
#endif // HAVE_LINUX_VIDEODEV_H
|
||||
#ifdef HAVE_LIBV4L1_VIDEODEV_H
|
||||
#include <libv4l1-videodev.h>
|
||||
#endif // HAVE_LIB4VL1_VIDEODEV_H
|
||||
#ifdef HAVE_LINUX_VIDEODEV2_H
|
||||
#include <linux/videodev2.h>
|
||||
#endif // HAVE_LINUX_VIDEODEV2_H
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/thr.h>
|
||||
#endif
|
||||
|
||||
bool Logger::smInitialised = false;
|
||||
Logger *Logger::smInstance = 0;
|
||||
|
@ -527,9 +530,25 @@ void Logger::logPrint( bool hex, const char * const file, const int line, const
|
|||
#endif
|
||||
|
||||
pid_t tid;
|
||||
#ifdef __FreeBSD__
|
||||
long lwpid;
|
||||
thr_self(&lwpid);
|
||||
tid = lwpid;
|
||||
|
||||
if (tid < 0 ) // Thread/Process id
|
||||
#else
|
||||
#ifdef HAVE_SYSCALL
|
||||
#ifdef __FreeBSD_kernel__
|
||||
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
|
||||
|
||||
# else
|
||||
// SOLARIS doesn't have SYS_gettid; don't assume
|
||||
#ifdef SYS_gettid
|
||||
if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id
|
||||
#endif // SYS_gettid
|
||||
#endif
|
||||
#endif // HAVE_SYSCALL
|
||||
#endif
|
||||
tid = getpid(); // Process id
|
||||
|
||||
char *logPtr = logString;
|
||||
|
|
|
@ -56,6 +56,11 @@
|
|||
#include <sys/shm.h>
|
||||
#endif // ZM_MEM_MAPPED
|
||||
|
||||
// SOLARIS - we don't have MAP_LOCKED on openSolaris/illumos
|
||||
#ifndef MAP_LOCKED
|
||||
#define MAP_LOCKED 0
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
std::vector<std::string> split(const std::string &s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
|
@ -252,7 +257,6 @@ bool Monitor::MonitorLink::hasAlarmed()
|
|||
else if( shared_data->last_event != (unsigned int)last_event )
|
||||
{
|
||||
last_event = shared_data->last_event;
|
||||
return( true );
|
||||
}
|
||||
return( false );
|
||||
}
|
||||
|
@ -442,7 +446,7 @@ Monitor::Monitor(
|
|||
}
|
||||
}
|
||||
|
||||
// Will this not happen everytime a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after..
|
||||
// Will this not happen every time a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after..
|
||||
if ( !n_zones ) {
|
||||
Debug( 1, "Monitor %s has no zones, adding one.", name );
|
||||
n_zones = 1;
|
||||
|
@ -531,14 +535,18 @@ bool Monitor::connect() {
|
|||
Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size );
|
||||
return false;
|
||||
} else {
|
||||
#ifdef MAP_LOCKED
|
||||
mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0 );
|
||||
if ( mem_ptr == MAP_FAILED ) {
|
||||
if ( errno == EAGAIN ) {
|
||||
Debug( 1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size );
|
||||
#endif
|
||||
mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 );
|
||||
Debug( 1, "Mapped file %s (%d bytes) to locked memory, unlocked", mem_file, mem_size );
|
||||
#ifdef MAP_LOCKED
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ( mem_ptr == MAP_FAILED )
|
||||
Fatal( "Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno );
|
||||
}
|
||||
|
@ -3101,7 +3109,7 @@ bool Monitor::closeEvent()
|
|||
* comparing it with ZM_COLOUR_RGB24 or ZM_COLOUR_RGB32 is the way ), and then
|
||||
* manage che check using RGB_VAL_RED() and so on macros instead of just RED().
|
||||
*
|
||||
* Be carefull that in 32 bit images we need to check also where the alpha channel is, so,
|
||||
* Be careful that in 32 bit images we need to check also where the alpha channel is, so,
|
||||
* (RGBA and BGRA) or (ABGR and ARGB) aren't the same!
|
||||
*
|
||||
* To check black pixels in 32 bit images i can do a more efficient way using
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue