---- syslog-ng-3.0.1/src/misc.c~ 2008-11-05 20:57:42.000000000 +0100
-+++ syslog-ng-3.0.1/src/misc.c 2009-01-16 11:43:30.896633603 +0100
-@@ -274,7 +274,7 @@
- struct passwd *pw;
+diff --git a/configure.in b/configure.in
+index d5f0769..1605bff 100644
+--- a/configure.in
++++ b/configure.in
+@@ -49,10 +49,8 @@ fi
- *uid = 0;
-- if (*user)
-+ if (!*user)
- return FALSE;
+ if test "x$prefix" = "xNONE"; then
+ prefix=$ac_default_prefix
+- pidfiledir="/var/run"
+-else
+- pidfiledir="${prefix}/var/run"
+ fi
++pidfiledir="${localstatedir}"
+
+ AM_CONFIG_HEADER(config.h)
+
+@@ -70,7 +68,7 @@ AC_ARG_WITH(pidfile-dir,
+
+ AC_ARG_WITH(timezone-dir,
+ [ --with-timezone-dir=path Use path as the directory to get the timezone files],
+- timezone_dir=$with_timezone_dir)
++ timezonedir=$with_timezone_dir)
+
+ AC_ARG_WITH(ld-library-path,
+ [ --with-ld-library-path=path Set LD_LIBRARY_PATH during runtime to the value given],
+@@ -92,10 +90,13 @@ AC_ARG_ENABLE(ssl,
+ [ --enable-ssl Enable SSL support.],,enable_ssl="auto")
+
+ AC_ARG_ENABLE(dynamic-linking,
+- [ --enable-dynamic-linking Link glib and eventlog dynamically instead of statically.])
++ [ --enable-dynamic-linking Link glib and eventlog dynamically instead of statically.],,enable_dynamic_linking="auto")
+
+ AC_ARG_ENABLE(static-linking,
+- [ --enable-static-linking Link everything statically.])
++ [ --enable-static-linking Link everything statically.],,enable_static_linking="auto")
++
++AC_ARG_ENABLE(mixed-linking,
++ [ --enable-mixed-linking Link 3rd party libraries statically, system libraries dynamically],,enable_mixed_linking="auto")
+
+ AC_ARG_ENABLE(ipv6,
+ [ --enable-ipv6 Enable support for IPv6.],,enable_ipv6="auto")
+@@ -319,9 +320,6 @@ dnl ***************************************************************************
+ dnl OpenSSL headers/libraries
+ dnl ***************************************************************************
+
+-OPENSSL_LIBS=""
+-OPENSSL_CPPFLAGS=""
+-
+ # openssl is needed for:
+ # * TLS support
+
+@@ -360,7 +358,13 @@ dnl libdbi headers/libraries
+ dnl ***************************************************************************
+
+ AC_CHECK_LIB(dl, dlsym, DL_LIBS="-ldl")
+-PKG_CHECK_MODULES(LIBDBI, dbi >= $LIBDBI_MIN_VERSION,, LIBDBI_LIBS="")
++PKG_CHECK_MODULES(LIBDBI, dbi >= $LIBDBI_MIN_VERSION,, libdbi_pkgconfig_not_found="1")
++
++if test "$libdbi_pkgconfig_not_found" -eq 1; then
++ dnl if libdbi has no .pc file, try it without one
++ AC_CHECK_LIB(dbi, dbi_initialize, LIBDBI_LIBS="-ldbi"; LIBDBI_CFLAGS="-I/usr/include")
++fi
++
+
+ dnl ***************************************************************************
+ dnl Some more checks based on the detected settings above
+@@ -606,8 +610,42 @@ int main()
+ fi
+ fi
+
+-if test "x$enable_dynamic_linking" = "xyes" -a "x$enable_static_linking" = "xyes"; then
+- AC_MSG_ERROR([You cannot specify dynamic and static linking at the same time.])
++if test "$enable_dynamic_linking" = "auto" -a "$enable_static_linking" = "auto" -a "$enable_mixed_linking" = "auto"; then
++ enable_dynamic_linking="yes"
++ enable_static_linking="no"
++ enable_mixed_linking="no"
++fi
++
++linkopts=0
++if test "x$enable_dynamic_linking" = "xyes"; then
++ linkopts=`expr $linkopts + 1`
++fi
++if test "x$enable_static_linking" = "xyes"; then
++ linkopts=`expr $linkopts + 1`
++fi
++if test "x$enable_mixed_linking" = "xyes"; then
++ linkopts=`expr $linkopts + 1`
++fi
++
++if test "$linkopts" -gt 1; then
++ AC_MSG_ERROR([You cannot specify multiple linking options at the same time (--enable-dynamic-linking, --enable-static-linking, --enable-mixed-linking).])
++fi
++
++if test "x$enable_dynamic_linking" = "xyes"; then
++ enable_dynamic_linking="yes"
++ enable_static_linking="no"
++ enable_mixed_linking="no"
++ linking_mode="dynamic"
++elif test "x$enable_static_linking" = "xyes"; then
++ enable_dynamic_linking="no"
++ enable_static_linking="yes"
++ enable_mixed_linking="no"
++ linking_mode="static"
++elif test "x$enable_mixed_linking" = "xyes"; then
++ enable_dynamic_linking="no"
++ enable_static_linking="no"
++ enable_mixed_linking="yes"
++ linking_mode="mixed"
+ fi
+
+ if test "x$enable_dynamic_linking" != "xyes" -a "x$blb_cv_static_glib" = "xno"; then
+@@ -615,7 +653,7 @@ if test "x$enable_dynamic_linking" != "xyes" -a "x$blb_cv_static_glib" = "xno";
+ fi
+
+ if test "x$enable_dynamic_linking" != "xyes" -a "x$blb_cv_static_openssl" = "xno"; then
+- AC_MSG_ERROR([static OpenSSL libraries not found (libssl.a and libcrypto.a), either link OpenSSL statically using the --enable-dynamic-linking, or install a static OpenSSL])
++ AC_MSG_ERROR([static OpenSSL libraries not found (libssl.a, libcrypto.a and their external dependencies like libz.a), either link OpenSSL statically using the --enable-dynamic-linking, or install a static OpenSSL])
+ fi
+
+
+@@ -672,8 +710,8 @@ AC_DEFINE_UNQUOTED(PATH_PREFIX, "`patheval $prefix`", [prefix directory])
+ AC_DEFINE_UNQUOTED(PATH_SYSCONFDIR, "`patheval $sysconfdir`", [sysconfdir])
+ AC_DEFINE_UNQUOTED(PATH_LOCALSTATEDIR, "`patheval $localstatedir`", [local state directory])
+ AC_DEFINE_UNQUOTED(PATH_PIDFILEDIR, "`patheval $pidfiledir`", [local state directory])
+-if test -n "$timezone_dir"; then
+- AC_DEFINE_UNQUOTED(PATH_TIMEZONEDIR, "`patheval $timezone_dir`", [timezone base directory])
++if test -n "$timezonedir"; then
++ AC_DEFINE_UNQUOTED(PATH_TIMEZONEDIR, "`patheval $timezonedir`", [timezone base directory])
+ fi
+ if test -n "$env_ld_library_path"; then
+ AC_DEFINE_UNQUOTED(ENV_LD_LIBRARY_PATH, "$env_ld_library_path", [set LD_LIBRARY_PATH to this value])
+@@ -695,6 +733,8 @@ AC_DEFINE_UNQUOTED(ENABLE_ENV_WRAPPER, `enable_value $enable_env_wrapper`, [Enab
+
+ AM_CONDITIONAL(ENABLE_ENV_WRAPPER, [test "$enable_env_wrapper" = "yes"])
+
++AC_SUBST(timezonedir)
++AC_SUBST(pidfiledir)
+ AC_SUBST(DEPS_CPPFLAGS)
+ AC_SUBST(DEPS_LIBS)
+ AC_SUBST(BASE_LIBS)
+@@ -729,6 +769,7 @@ echo " compiler : $CC"
+ echo " compiler options : $CFLAGS $CPPFLAGS"
+ echo " linker flags : $LDFLAGS $LIBS"
+ echo " prefix : $prefix"
++echo " linking mode : $linking_mode"
+ echo " Features:"
+ echo " Sun STREAMS support : ${enable_sun_streams:=no}"
+ echo " Sun Door support : ${enable_sun_door:=no}"
+diff --git a/contrib/balabit-initscripts/init-functions b/contrib/balabit-initscripts/init-functions
+index e1898a8..c3b18ef 100644
+--- a/contrib/balabit-initscripts/init-functions
++++ b/contrib/balabit-initscripts/init-functions
+@@ -6,12 +6,35 @@ NORMAL=
+ FANCYTTY=
+ PSOPTS=
+
+-case `uname -s` in
++ECHO=echo
++
++OS=`uname -s`
++
++disable_xpg_echo() {
++ # \X chars only passed to echo under bash, if xpg_echo enabled or echo -e
++ # used on Linux.
++ if [ -n "$BASH_VERSION" ];then
++ shopt -s xpg_echo
++ fi
++}
++
++case $OS in
+ # default ps -e cuts the process' name at 8 characters, so we have to list it
+ # in a long form
+- SunOS) PSOPTS=" -o pid -o tty -o time -o comm" ;;
++ SunOS)
++ PSOPTS=" -o pid -o tty -o time -o comm"
++ disable_xpg_echo
++ ;;
++ Linux)
++ if [ -z "$BASH_VERSION" ]; then
++ # beware of dash's builtin echo ...
++ ECHO="/bin/echo -e"
++ fi
++ ;;
++ *) disable_xpg_echo ;;
+ esac
+
++
+ _checkpid() {
+ _pid=$1
+ _proc=$2
+@@ -30,7 +53,7 @@ _pid_from_pidfile() {
+ pid=
+
+ if [ -f "$pidfile" ];then
+- pid=`head -1 $pidfile`
++ pid=`head -1 $pidfile 2> /dev/null`
+ if [ $? -ne 0 ]; then
+ # on slow machines (or ones under high load) the pidfile could be
+ # erased between -f and `head` ...
+@@ -195,17 +218,17 @@ log_use_fancy_output() {
+
+
+ log_success_msg() {
+- echo "$@"
++ $ECHO "$@"
+ }
+
+ log_failure_msg() {
+ log_use_fancy_output
+- echo "${RED}$@${NORMAL}"
++ $ECHO "${RED}$@${NORMAL}"
+ }
+
+ log_warning_msg() {
+ log_use_fancy_output
+- echo "${YELLOW}$@${NORMAL}"
++ $ECHO "${YELLOW}$@${NORMAL}"
+ }
+
+ # NON-LSB Functions
+@@ -215,7 +238,7 @@ log_begin_msg() {
+ return 1
+ fi
+
+- echo "$@\c "
++ $ECHO "$@\c "
+ }
+
+ log_daemon_msg() {
+@@ -224,11 +247,11 @@ log_daemon_msg() {
+ fi
+
+ if [ -z "$2" ]; then
+- echo "$1:\c "
++ $ECHO "$1:\c "
+ return
+ fi
+
+- echo "$1: $2\c "
++ $ECHO "$1: $2\c "
+ }
+
+ log_progress_msg() {
+@@ -237,9 +260,9 @@ log_progress_msg() {
+ fi
+
+ if [ $1 -eq 0 ]; then
+- echo "."
++ $ECHO "."
+ else
+- echo " failed"
++ $ECHO " failed"
+ fi
+ }
+
+@@ -250,23 +273,23 @@ log_end_msg() {
+
+ log_fancy_output
+ if [ $1 -eq 0 ];then
+- echo "."
++ $ECHO "."
+ else
+- echo "${RED}failed!${NORMAL}"
++ $ECHO "${RED}failed!${NORMAL}"
+ fi
+ return $1
+ }
+
+ log_action_msg() {
+- echo "$@."
++ $ECHO "$@."
+ }
+
+ log_action_begin_msg() {
+- echo "$@...\c "
++ $ECHO "$@...\c "
+ }
+
+ log_action_cont_msg() {
+- echo "$@...\c "
++ $ECHO "$@...\c "
+ }
+
+ log_action_end_msg() {
+@@ -278,15 +301,12 @@ log_action_end_msg() {
+
+ log_fancy_output
+ if [ $1 -eq 0 ]; then
+- echo "done${end}"
++ $ECHO "done${end}"
+ else
+- echo "${RED}failed${end}${NORMAL}"
++ $ECHO "${RED}failed${end}${NORMAL}"
+ fi
+ }
+
+-# \X chars only passed to echo under bash, if xpg_echo enabled....
+-if [ -n "$BASH_VERSION" ];then
+- shopt -s xpg_echo
+-fi
+
+ # vim: ft=sh ts=2 expandtab
++
+diff --git a/contrib/balabit-initscripts/init.d b/contrib/balabit-initscripts/init.d
+index ff2e249..589da86 100644
+--- a/contrib/balabit-initscripts/init.d
++++ b/contrib/balabit-initscripts/init.d
+@@ -25,6 +25,7 @@ SYSLOGNG_PREFIX=/opt/syslog-ng
+ SYSLOGNG="$SYSLOGNG_PREFIX/sbin/syslog-ng"
+ CONFFILE=$SYSLOGNG_PREFIX/etc/syslog-ng.conf
+ PIDFILE=$SYSLOGNG_PREFIX/var/run/syslog-ng.pid
++SYSLOGPIDFILE="/var/run/syslog.pid"
+
+ INIT_FUNCTIONS=/lib/lsb/init-functions
+ SLNG_INIT_FUNCTIONS=$SYSLOGNG_PREFIX/lib/init-functions
+@@ -64,6 +65,17 @@ if [ -f /etc/lsb-release ]; then
+ . /etc/lsb-release
+ fi
+
++if [ -f "/etc/redhat-release" ];then
++ # redhat uses a different syslogd pidfile...
++ SYSLOGPIDFILE="/var/run/syslogd.pid"
++fi
++
++if [ "$OS" = "SunOS" ] || [ "$OS" = "Solaris" ];then
++ if [ "`uname -r`" = "5.8" ];then
++ SYSLOGPIDFILE="/etc/syslog.pid"
++ fi
++fi
++
+ if [ -f /lib/lsb/init-functions ];then
+ # long list of exclusions...
+ if [ -f "/etc/redhat-release" ] || [ -f "/etc/SuSE-release" ];then
+@@ -117,7 +129,7 @@ check_syntax() {
+
+ slng_waitforpid() {
+ _pid=$1
+- _process=$2
++ _process=$2
+ _cnt=$MAXWAIT
+
+ # no pid, return...
+@@ -147,6 +159,11 @@ returnmessage() {
+
+ syslogng_start() {
+ echo_n "Starting syslog-ng: "
++ PID=`pidofproc -p ${PIDFILE} ${SYSLOGNG} | head -1`
++ if [ -n "$PID" ] && [ $PID -gt 0 ] ;then
++ log_success_msg "already running: $PID"
++ return $retval
++ fi
+ start_daemon -p ${PIDFILE} ${SYSLOGNG} ${SYSLOGNG_OPTIONS}
+ retval=$?
+ returnmessage $retval
+@@ -154,6 +171,13 @@ syslogng_start() {
+ if [ "$OS" = "Linux" ] && [ -d $SUBSYSDIR ];then
+ touch $SUBSYSDIR/syslog-ng
+ fi
++ # remove symlinks
++ if [ -h $SYSLOGPIDFILE ];then
++ rm -f $SYSLOGPIDFILE
++ fi
++ if [ ! -f $SYSLOGPIDFILE ];then
++ ln -s $PIDFILE $SYSLOGPIDFILE
++ fi
+ fi
+ return $retval
+ }
+@@ -180,6 +204,9 @@ syslogng_stop() {
+ fi
+ if [ $retval -eq 0 ];then
+ rm -f $SUBSYSDIR/syslog-ng ${PIDFILE}
++ if [ -h $SYSLOGPIDFILE ];then
++ rm -f $SYSLOGPIDFILE
++ fi
+ fi
+ return $retval
+ }
+@@ -270,6 +297,14 @@ case "$1" in
+ force-reload)
+ syslogng_restart
+ ;;
++ reload-or-restart)
++ PID=`pidofproc -p ${PIDFILE} ${SYSLOGNG} | head -1`
++ if [ -n "$PID" ] && [ $PID -gt 0 ] ;then
++ syslogng_reload
++ else
++ syslogng_start
++ fi
++ ;;
+ status)
+ syslogng_status
+ ;;
+@@ -284,4 +319,4 @@ esac
+
+ exit $retval
+
+-# vim: ts=2 ft=sh
++# vim: ts=2 ft=sh noexpandtab
+diff --git a/contrib/balabit-initscripts/init.d.freebsd b/contrib/balabit-initscripts/init.d.freebsd
+index 997b4db..de04473 100644
+--- a/contrib/balabit-initscripts/init.d.freebsd
++++ b/contrib/balabit-initscripts/init.d.freebsd
+@@ -33,9 +33,13 @@ command="$SYSLOGNG_PREFIX/sbin/syslog-ng"
+ required_files="$SYSLOGNG_PREFIX/etc/syslog-ng.conf"
+
+ start_precmd="syslog_ng_start_precmd"
++start_postcmd="syslog_ng_start_postcmd"
++stop_postcmd="syslog_ng_stop_postcmd"
+ reload_precmd="syslog_ng_reload_precmd"
+ extra_commands="reload"
+
++# get original syslog pidfile from initscript.
++_syslogd_pidfile=`sed -n -e 's/^pidfile="\([^"]*\)"/\1/p' /etc/rc.d/syslogd 2> /dev/null`
+ syslog_ng_start_precmd() {
+ if [ ! -L /dev/log ]; then
+ ln -s /var/run/log /dev/log
+@@ -50,6 +54,26 @@ syslog_ng_reload_precmd() {
+ fi
+ }
+
++syslog_ng_start_postcmd() {
++ if [ -n "$_syslogd_pidfile" ]; then
++ # remove symlinks
++ if [ -h $_syslogd_pidfile ]; then
++ rm -f $_syslogd_pidfile
++ fi
++ if [ ! -f $_syslogd_pidfile ]; then
++ ln -s "$pidfile" "$_syslogd_pidfile"
++ fi
++ fi
++}
++
++syslog_ng_stop_postcmd() {
++ if [ -n "$_syslogd_pidfile" ]; then
++ if [ -h $_syslogd_pidfile ]; then
++ rm -f "$_syslogd_pidfile"
++ fi
++ fi
++}
++
+ load_rc_config "$name"
+
+ case $1 in
+diff --git a/contrib/cygwin-packaging/cygwin-postinstall b/contrib/cygwin-packaging/cygwin-postinstall
+index 4b7bf7d..e812ead 100755
+--- a/contrib/cygwin-packaging/cygwin-postinstall
++++ b/contrib/cygwin-packaging/cygwin-postinstall
+@@ -21,11 +21,11 @@ then
+ exit 3
+ fi
+ mkdir -p "${DESTDIR}/usr/bin"
+-mkdir -p "${DESTDIR}/usr/share/doc/syslog-ng"
++#mkdir -p "${DESTDIR}/usr/share/doc/syslog-ng"
+ mkdir -p "${DESTDIR}/usr/share/doc/Cygwin"
+ cp contrib/cygwin-packaging/syslog-ng-config "${DESTDIR}/usr/bin"
+-cp -rp doc/examples/syslog-ng.conf.s* doc/reference/syslog-ng.[tx]* "${DESTDIR}/usr/share/doc/syslog-ng"
+-tar xzfC doc/reference/syslog-ng.html.tar.gz "${DESTDIR}/usr/share/doc/syslog-ng"
++#cp -rp doc/examples/syslog-ng.conf.s* doc/reference/syslog-ng.[tx]* "${DESTDIR}/usr/share/doc/syslog-ng"
++#tar xzfC doc/reference/syslog-ng.html.tar.gz "${DESTDIR}/usr/share/doc/syslog-ng"
+ cat > "${DESTDIR}/usr/share/doc/Cygwin/syslog-ng.README" <<'EOF'
+ If you want to use syslog-ng, just run the /usr/bin/syslog-ng-config
+ script. This script will create a default configuration file
+@@ -42,15 +42,15 @@ The syslog-ng package has been built using the following command
+ sequence from the top level source dir:
+
+ ./configure \
+- --disable-ipv6 \
+- --disable-tcp-wrapper \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --libexecdir='$(prefix)/sbin' \
+ --localstatedir=/var \
+ --datadir='$(prefix)/share' \
+ --mandir='$(prefix)/share/man' \
+- --infodir='$(prefix)/share/info'
++ --infodir='$(prefix)/share/info' \
++ --enable-dynamic-linking \
++ --with-pidfile-dir=/var
+ make
+ make install-strip
+ contrib/cygwin-packaging/cygwin-postinstall
+diff --git a/contrib/cygwin-packaging/syslog-ng-config b/contrib/cygwin-packaging/syslog-ng-config
+index 790f0cc..7ae5fec 100755
+--- a/contrib/cygwin-packaging/syslog-ng-config
++++ b/contrib/cygwin-packaging/syslog-ng-config
+@@ -205,13 +205,13 @@ if [ ! -f "${SYSCONFDIR}/syslog-ng.conf" ]
+ then
+ echo "Creating default ${SYSCONFDIR}/syslog-ng.conf file"
+ cat > ${SYSCONFDIR}/syslog-ng.conf << EOF
++@version 3.0
+ options {
+ keep_hostname(yes);
+- chain_hostnames(no);
+ owner("system");
+ group("root");
+ perm(0664);
+- sync(0);
++ flush_lines(0);
+ };
+
+ source applications {
+@@ -220,7 +220,7 @@ source applications {
+ };
+
+ source kernel {
+- file("/dev/kmsg", log_prefix("kernel: "));
++ file("/dev/kmsg", program_override("kernel: "));
+ };
+
+ destination messages {
+@@ -240,42 +240,35 @@ EOF
+ fi
+ setfacl -m u:system:rw- "${SYSCONFDIR}/syslog-ng.conf"
+
+-# Check if running on NT
+-_sys="`uname`"
+-_nt=`expr "${_sys}" : "CYGWIN_NT"`
+-# On NT ask if syslog-ng should be installed as service
+-if [ ${_nt} -gt 0 ]
++# Check if syslogd is installed and remove on user request.
++if cygrunsrv -Q syslogd > /dev/null 2>&1
+ then
+- # Check if syslogd is installed and remove on user request.
+- if cygrunsrv -Q syslogd > /dev/null 2>&1
++ echo "Warning: The syslogd service is already installed. You can not"
++ echo "run both, syslogd and syslog-ng in parallel."
++ echo
++ if request "Do you want to deinstall the syslogd service in favor of syslog-ng?"
+ then
+- echo "Warning: The syslogd service is already installed. You can not"
+- echo "run both, syslogd and syslog-ng in parallel."
+- echo
+- if request "Do you want to deinstall the syslogd service in favor of syslog-ng?"
+- then
+- cygrunsrv -E syslogd
+- cygrunsrv -R syslogd
+- fi
++ cygrunsrv -E syslogd
++ cygrunsrv -R syslogd
+ fi
+- # Install syslog-ng service if it is not already installed
+- if ! cygrunsrv -Q syslog-ng > /dev/null 2>&1
++fi
++# Install syslog-ng service if it is not already installed
++if ! cygrunsrv -Q syslog-ng > /dev/null 2>&1
++then
++ echo
++ echo
++ echo "Warning: The following function requires administrator privileges!"
++ echo
++ echo "Do you want to install syslog-ng as service?"
++ if request "(Say \"no\" if it's already installed as service)"
+ then
+- echo
+- echo
+- echo "Warning: The following function requires administrator privileges!"
+- echo
+- echo "Do you want to install syslog-ng as service?"
+- if request "(Say \"no\" if it's already installed as service)"
++ if cygrunsrv -I syslog-ng -d "CYGWIN syslog-ng" -p /usr/sbin/syslog-ng -a "-F --fd-limit 256"
+ then
+- if cygrunsrv -I syslog-ng -d "CYGWIN syslog-ng" -p /usr/sbin/syslog-ng -a -F
+- then
+- echo
+- echo "The service has been installed under LocalSystem account."
+- echo "To start the service, call \`net start syslog-ng' or \`cygrunsrv -S syslog-ng'."
+- echo
+- echo "Check ${SYSCONFDIR}/syslog-ng.conf first, if it suits your needs."
+- fi
++ echo
++ echo "The service has been installed under LocalSystem account."
++ echo "To start the service, call \`net start syslog-ng' or \`cygrunsrv -S syslog-ng'."
++ echo
++ echo "Check ${SYSCONFDIR}/syslog-ng.conf first, if it suits your needs."
+ fi
+ fi
+ fi
+diff --git a/contrib/solaris-packaging/syslog-ng.method b/contrib/solaris-packaging/syslog-ng.method
+index f0fee58..d819a3c 100755
+--- a/contrib/solaris-packaging/syslog-ng.method
++++ b/contrib/solaris-packaging/syslog-ng.method
+@@ -13,6 +13,7 @@ SYSLOGNG_PREFIX=/opt/syslog-ng
+ SYSLOGNG="$SYSLOGNG_PREFIX/sbin/syslog-ng"
+ CONFFILE=$SYSLOGNG_PREFIX/etc/syslog-ng.conf
+ PIDFILE=$SYSLOGNG_PREFIX/var/run/syslog-ng.pid
++SYSLOGPIDFILE=/var/run/syslog.pid
+
+ OPTIONS=
+ MAXWAIT=30
+@@ -56,7 +57,7 @@ slng_stop() {
+
+ _process=`basename $SYSLOGNG`
+ slng_waitforpid "$_process" $syspid
+- _ret=$?
++ _ret=$?
+ if [ $_ret -eq 0 ]; then
+ kill -KILL $syspid
+ $_ret=$?
+@@ -68,6 +69,9 @@ slng_stop() {
+ [ $? -ne 0 ] && exit $SMF_EXIT_ERR_FATAL
+ fi
+ rm -f $PIDFILE
++ if [ -h $SYSLOGPIDFILE ];then
++ rm -f $SYSLOGPIDFILE
++ fi
+ return $SMF_EXIT_OK
+ fi
+ return $SMF_EXIT_ERR_FATAL
+@@ -93,6 +97,13 @@ slng_start () {
+ fi
+ check_syntax
+ $SYSLOGNG $OPTIONS
++ # remove symlinks
++ if [ -h $SYSLOGPIDFILE ];then
++ rm -f $SYSLOGPIDFILE
++ fi
++ if [ ! -f $SYSLOGPIDFILE ];then
++ ln -s $PIDFILE $SYSLOGPIDFILE
++ fi
+ return $SMF_EXIT_OK
+ fi
+ return $SMF_EXIT_ERR_FATAL
+diff --git a/src/affile.c b/src/affile.c
+index 6d48915..5721a1a 100644
+--- a/src/affile.c
++++ b/src/affile.c
+@@ -40,11 +40,12 @@
+
+ static gboolean
+ affile_open_file(gchar *name, gint flags,
+- uid_t uid, gid_t gid, mode_t mode,
+- uid_t dir_uid, gid_t dir_gid, mode_t dir_mode,
+- gboolean create_dirs, gboolean privileged, gint *fd)
++ uid_t uid, gid_t gid, mode_t mode,
++ uid_t dir_uid, gid_t dir_gid, mode_t dir_mode,
++ gboolean create_dirs, gboolean privileged, gboolean is_pipe, gint *fd)
+ {
+ cap_t saved_caps;
++ struct stat st;
+
+ if (strstr(name, "../") || strstr(name, "/.."))
+ {
+@@ -63,20 +64,43 @@ affile_open_file(gchar *name, gint flags,
+ g_process_cap_modify(CAP_DAC_READ_SEARCH, TRUE);
+ g_process_cap_modify(CAP_SYS_ADMIN, TRUE);
+ }
++ if (stat(name, &st) >= 0)
++ {
++ if (is_pipe && !S_ISFIFO(st.st_mode))
++ {
++ msg_error("Error opening pipe, underlying file is not a FIFO, it should be used by file()",
++ evt_tag_str("filename", name),
++ NULL);
++ goto exit;
++ }
++ else if (!is_pipe && S_ISFIFO(st.st_mode))
++ {
++ msg_error("Error opening file, underlying file is a FIFO, it should be used by pipe()",
++ evt_tag_str("filename", name),
++ NULL);
++ goto exit;
++ }
++ }
+ *fd = open(name, flags, mode);
++ if (is_pipe && *fd < 0 && errno == ENOENT)
++ {
++ if (mkfifo(name, 0666) >= 0)
++ *fd = open(name, flags, 0666);
++ }
+
+ if (*fd != -1)
+ {
+ g_fd_set_cloexec(*fd, TRUE);
+
+ g_process_cap_modify(CAP_DAC_OVERRIDE, TRUE);
+- if (uid != -1)
++ if (uid != (uid_t) -1)
+ fchown(*fd, uid, -1);
+- if (gid != -1)
++ if (gid != (gid_t) -1)
+ fchown(*fd, -1, gid);
+- if (mode != -1)
++ if (mode != (mode_t) -1)
+ fchmod(*fd, mode);
+ }
++ exit:
+ if (privileged)
+ {
+ g_process_cap_restore(saved_caps);
+@@ -99,7 +123,7 @@ affile_sd_open_file(AFFileSourceDriver *self, gchar *name, gint *fd)
+ else
+ flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
+
+- if (affile_open_file(name, flags, -1, -1, -1, 0, 0, 0, 0, !!(self->flags & AFFILE_PRIVILEGED), fd))
++ if (affile_open_file(name, flags, -1, -1, -1, 0, 0, 0, 0, !!(self->flags & AFFILE_PRIVILEGED), !!(self->flags & AFFILE_PIPE), fd))
+ return TRUE;
+ return FALSE;
+ }
+@@ -196,9 +220,15 @@ affile_sd_notify(LogPipe *s, LogPipe *sender, gint notify_code, gpointer user_da
+ transport = log_transport_plain_new(fd, 0);
+ transport->timeout = 10;
+
+- self->reader = log_reader_new(log_proto_plain_new_server(transport, self->reader_options.padding, self->reader_options.msg_size, LPPF_NOMREAD | ((self->reader_options.follow_freq > 0) ? LPPF_IGNORE_EOF : 0)),
+- LR_LOCAL);
+-
++ self->reader = log_reader_new(
++ log_proto_plain_new_server(transport, self->reader_options.padding,
++ self->reader_options.msg_size,
++ ((self->reader_options.follow_freq > 0)
++ ? LPPF_IGNORE_EOF
++ : LPPF_NOMREAD)
++ ),
++ LR_LOCAL);
++
+ log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.id, self->filename->str);
+
+ log_reader_set_follow_filename(self->reader, self->filename->str);
+@@ -290,10 +320,16 @@ affile_sd_init(LogPipe *s)
+ transport->timeout = 10;
+
+ /* FIXME: we shouldn't use reader_options to store log protocol parameters */
+- self->reader = log_reader_new(log_proto_plain_new_server(transport, self->reader_options.padding, self->reader_options.msg_size, LPPF_NOMREAD | ((self->reader_options.follow_freq > 0) ? LPPF_IGNORE_EOF : 0)),
+- LR_LOCAL);
++ self->reader = log_reader_new(
++ log_proto_plain_new_server(transport, self->reader_options.padding,
++ self->reader_options.msg_size,
++ ((self->reader_options.follow_freq > 0)
++ ? LPPF_IGNORE_EOF
++ : LPPF_NOMREAD)
++ ),
++ LR_LOCAL);
+ log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.id, self->filename->str);
+-
++
+ log_reader_set_follow_filename(self->reader, self->filename->str);
+
+ /* NOTE: if the file could not be opened, we ignore the last
+@@ -458,7 +494,7 @@ affile_dw_init(LogPipe *s)
+ if (affile_open_file(self->filename->str, flags,
+ self->owner->file_uid, self->owner->file_gid, self->owner->file_perm,
+ self->owner->dir_uid, self->owner->dir_gid, self->owner->dir_perm,
+- !!(self->owner->flags & AFFILE_CREATE_DIRS), FALSE, &fd))
++ !!(self->owner->flags & AFFILE_CREATE_DIRS), FALSE, !!(self->owner->flags & AFFILE_PIPE), &fd))
+ {
+ guint write_flags;
+
+diff --git a/src/afsocket.c b/src/afsocket.c
+index ad8e198..af788f6 100644
+--- a/src/afsocket.c
++++ b/src/afsocket.c
+@@ -90,12 +90,12 @@ afsocket_open_socket(GSockAddr *bind_addr, int stream_or_dgram, int *fd)
+ else
+ sock = socket(bind_addr->sa.sa_family, SOCK_DGRAM, 0);
- pw = getpwnam(user);
-commit 11f8d45b016107a686dbfa29497960ae3f6145ac
-Author: Balazs Scheidler <bazsi@balabit.hu>
-Date: Fri Jan 16 14:44:53 2009 +0100
-
- [config parser] "syslog" became a reserved word, make it possible to use that as a facility name
-
- In syslog-ng 3.0, "syslog" became a reserved word, thus the facility()
- filter couldn't use it as name for the facility named syslog.
-
- To avoid having to quote this word, I added a kludge to the
- config grammar, to make it recognize syslog as a facility name
- based on context.
-
+- g_fd_set_nonblock(sock, TRUE);
+- g_fd_set_cloexec(sock, TRUE);
+ if (sock != -1)
+ {
+ cap_t saved_caps;
+
++ g_fd_set_nonblock(sock, TRUE);
++ g_fd_set_cloexec(sock, TRUE);
+ saved_caps = g_process_cap_save();
+ g_process_cap_modify(CAP_NET_BIND_SERVICE, TRUE);
+ g_process_cap_modify(CAP_DAC_OVERRIDE, TRUE);
+@@ -208,7 +208,9 @@ afsocket_sc_init(LogPipe *s)
+ if ((self->owner->flags & AFSOCKET_SYSLOG_PROTOCOL) == 0)
+ {
+ /* plain protocol */
+- proto = log_proto_plain_new_server(transport, self->owner->reader_options.padding, self->owner->reader_options.msg_size, (self->owner->flags & AFSOCKET_DGRAM) ? LPPF_PKTTERM : 0);
++ proto = log_proto_plain_new_server(transport, self->owner->reader_options.padding,
++ self->owner->reader_options.msg_size,
++ (self->owner->flags & AFSOCKET_DGRAM) ? (LPPF_PKTTERM + LPPF_IGNORE_EOF) : 0);
+ }
+ else
+ {
+diff --git a/src/afsql.c b/src/afsql.c
+index 96c5b22..dcbc02e 100644
+--- a/src/afsql.c
++++ b/src/afsql.c
+@@ -940,6 +940,7 @@ afsql_dd_new()
+ self->frac_digits = -1;
+
+ self->validated_tables = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
++ g_static_mutex_init(&self->queue_lock);
+
+ init_sequence_number(&self->seq_num);
+ return &self->super;
diff --git a/src/cfg-grammar.y b/src/cfg-grammar.y
-index c40b7fb..d54ba8f 100644
+index 9902d84..2ad453a 100644
--- a/src/cfg-grammar.y
+++ b/src/cfg-grammar.y
-@@ -277,6 +277,7 @@ cfg_check_template(LogTemplate *template)
+@@ -52,6 +52,7 @@ LogParser *last_parser;
+ FilterRE *last_re_filter;
+ LogRewrite *last_rewrite;
+ gint last_addr_family = AF_INET;
++gchar *last_include_file;
+
+ #if ENABLE_SSL
+ TLSContext *last_tls_context;
+@@ -92,17 +93,20 @@ cfg_check_template(LogTemplate *template)
+ return TRUE;
+ }
+
++
+ %}
+
+ %union {
++ gint token;
+ gint64 num;
++ double fnum;
+ char *cptr;
+ void *ptr;
+ FilterExprNode *node;
+ }
+
+ /* statements */
+-%token KW_SOURCE KW_FILTER KW_PARSER KW_DESTINATION KW_LOG KW_OPTIONS
++%token KW_SOURCE KW_FILTER KW_PARSER KW_DESTINATION KW_LOG KW_OPTIONS KW_INCLUDE
+
+ /* source & destination items */
+ %token KW_INTERNAL KW_FILE KW_PIPE KW_UNIX_STREAM KW_UNIX_DGRAM
+@@ -154,7 +158,7 @@ cfg_check_template(LogTemplate *template)
+
+ /* socket related options */
+ %token KW_KEEP_ALIVE KW_MAX_CONNECTIONS
+-%token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT KW_FRAMED
++%token KW_LOCALIP KW_IP KW_LOCALPORT KW_PORT KW_DESTPORT
+ %token KW_IP_TTL KW_SO_BROADCAST KW_IP_TOS KW_SO_SNDBUF KW_SO_RCVBUF KW_SO_KEEPALIVE KW_SPOOF_SOURCE
+
+ /* misc options */
+@@ -182,6 +186,7 @@ cfg_check_template(LogTemplate *template)
+ %token DOTDOT
+ %token <cptr> IDENTIFIER
+ %token <num> NUMBER
++%token <fnum> FLOAT
+ %token <cptr> STRING
- %type <cptr> string
- %type <cptr> string_or_number
-+%type <cptr> facility_string
+ %left KW_OR
+@@ -276,6 +281,32 @@ cfg_check_template(LogTemplate *template)
%type <ptr> string_list
%type <ptr> string_list_build
-@@ -464,7 +465,7 @@ source_affile_option
++%type <token> reserved_words_as_strings
++
++%type <token> KW_PARSER
++%type <token> KW_REWRITE
++%type <token> KW_INCLUDE
++%type <token> KW_SYSLOG
++%type <token> KW_COLUMNS
++%type <token> KW_DELIMITERS
++%type <token> KW_QUOTES
++%type <token> KW_QUOTE_PAIRS
++%type <token> KW_NULL
++%type <token> KW_CSV_PARSER
++%type <token> KW_DB_PARSER
++%type <token> KW_ENCODING
++%type <token> KW_SET
++%type <token> KW_SUBST
++%type <token> KW_VALUE
++%type <token> KW_PROGRAM_OVERRIDE
++%type <token> KW_HOST_OVERRIDE
++%type <token> KW_TRANSPORT
++%type <token> KW_TRUSTED_KEYS
++%type <token> KW_TRUSTED_DN
++%type <token> KW_MESSAGE
++%type <token> KW_TYPE
++%type <token> KW_SQL
++
+ %%
+
+ start
+@@ -283,7 +314,21 @@ start
+ ;
+
+ stmts
+- : stmt ';' stmts
++ : stmt ';'
++ {
++ if (last_include_file && !cfg_lex_process_include(last_include_file))
++ {
++ free(last_include_file);
++ last_include_file = NULL;
++ YYERROR;
++ }
++ if (last_include_file)
++ {
++ free(last_include_file);
++ last_include_file = NULL;
++ }
++ }
++ stmts
+ |
+ ;
+
+@@ -296,6 +341,7 @@ stmt
+ | KW_REWRITE rewrite_stmt { cfg_add_rewrite(configuration, $2); }
+ | KW_TEMPLATE template_stmt { cfg_add_template(configuration, $2); }
+ | KW_OPTIONS options_stmt { }
++ | KW_INCLUDE include_stmt { }
+ ;
+
+ source_stmt
+@@ -319,6 +365,9 @@ dest_stmt
+ log_stmt
+ : '{' log_items log_forks log_flags '}' { LogPipeItem *pi = log_pipe_item_append_tail($2, $3); $$ = log_connection_new(pi, $4); }
+ ;
++
++include_stmt
++ : string { last_include_file = $1; }
+
+ log_items
+ : log_item ';' log_items { log_pipe_item_append($1, $3); $$ = $1; }
+@@ -442,7 +491,7 @@ source_affile_option
affile_sd_set_pri_level(last_driver, level);
free($3);
}
- | KW_FACILITY '(' string ')'
-+ | KW_FACILITY '(' facility_string ')'
++ | KW_FACILITY '(' string ')'
{
int facility = -1;
-@@ -1305,7 +1306,7 @@ filter_fac_list
+@@ -708,7 +757,8 @@ source_reader_option
+ | KW_LOG_MSG_SIZE '(' NUMBER ')' { last_reader_options->msg_size = $3; }
+ | KW_LOG_FETCH_LIMIT '(' NUMBER ')' { last_reader_options->fetch_limit = $3; }
+ | KW_PAD_SIZE '(' NUMBER ')' { last_reader_options->padding = $3; }
+- | KW_FOLLOW_FREQ '(' NUMBER ')' { last_reader_options->follow_freq = $3; }
++ | KW_FOLLOW_FREQ '(' FLOAT ')' { last_reader_options->follow_freq = (long) ($3 * 1000); }
++ | KW_FOLLOW_FREQ '(' NUMBER ')' { last_reader_options->follow_freq = ($3 * 1000); }
+ | KW_KEEP_TIMESTAMP '(' yesno ')' { last_reader_options->super.keep_timestamp = $3; }
+ | KW_ENCODING '(' string ')' { last_reader_options->text_encoding = g_strdup($3); free($3); }
+ ;
+@@ -777,7 +827,7 @@ dest_afpipe
+ dest_afpipe_params
+ : string
+ {
+- last_driver = affile_dd_new($1, AFFILE_NO_EXPAND | AFFILE_PIPE);
++ last_driver = affile_dd_new($1, AFFILE_PIPE);
+ free($1);
+ last_writer_options = &((AFFileDestDriver *) last_driver)->writer_options;
+ last_writer_options->flush_lines = 0;
+@@ -1282,7 +1332,7 @@ filter_fac_list
;
filter_fac
- : string
-+ : facility_string
++ : string
{
int n = syslog_name_lookup_facility_by_name($1);
if (n == -1)
-@@ -1499,6 +1500,11 @@ string_list_build
- | { $$ = NULL; }
- ;
+@@ -1461,6 +1511,34 @@ dnsmode
+ string
+ : IDENTIFIER
+ | STRING
++ | reserved_words_as_strings { $$ = cfg_lex_get_keyword_string($1); }
++ ;
++
++reserved_words_as_strings
++ /* these keywords were introduced in syslog-ng 3.0 */
++ : KW_PARSER
++ | KW_REWRITE
++ | KW_INCLUDE
++ | KW_SYSLOG
++ | KW_COLUMNS
++ | KW_DELIMITERS
++ | KW_QUOTES
++ | KW_QUOTE_PAIRS
++ | KW_NULL
++ | KW_CSV_PARSER
++ | KW_DB_PARSER
++ | KW_ENCODING
++ | KW_SET
++ | KW_SUBST
++ | KW_VALUE
++ | KW_PROGRAM_OVERRIDE
++ | KW_HOST_OVERRIDE
++ | KW_TRANSPORT
++ | KW_TRUSTED_KEYS
++ | KW_TRUSTED_DN
++ | KW_MESSAGE
++ | KW_TYPE
++ | KW_SQL
+ ;
+
+ string_or_number
+@@ -1483,14 +1561,8 @@ extern int linenum;
+ void
+ yyerror(char *msg)
+ {
+- fprintf(stderr, "%s in %s at line %d.\n", msg, configuration->filename, linenum);
++ fprintf(stderr, "%s in %s at line %d.\n\n"
++ "syslog-ng documentation: http://www.balabit.com/support/documentation/?product=syslog-ng\n"
++ "mailing list: https://lists.balabit.hu/mailman/listinfo/syslog-ng\n", msg, cfg_lex_get_current_file(), cfg_lex_get_current_lineno());
+ }
+
+-void
+-yyparser_reset(void)
+-{
+- last_driver = NULL;
+- last_reader_options = NULL;
+- last_writer_options = NULL;
+- last_template = NULL;
+-}
+diff --git a/src/cfg-lex.l b/src/cfg-lex.l
+index c9db716..dba726a 100644
+--- a/src/cfg-lex.l
++++ b/src/cfg-lex.l
+@@ -31,6 +31,7 @@
+
+ #include <string.h>
+ #include <strings.h>
++#include <sys/stat.h>
+
+ struct keyword
+ {
+@@ -52,6 +53,7 @@ static struct keyword keywords[] = {
+ { "destination", KW_DESTINATION },
+ { "log", KW_LOG },
+ { "options", KW_OPTIONS },
++ { "include", KW_INCLUDE },
+
+ /* source or destination items */
+ { "file", KW_FILE },
+@@ -162,7 +164,6 @@ static struct keyword keywords[] = {
+ { "localport", KW_LOCALPORT },
+ { "port", KW_PORT },
+ { "destport", KW_DESTPORT },
+- { "framed", KW_FRAMED },
+ { "ip_ttl", KW_IP_TTL },
+ { "ip_tos", KW_IP_TOS },
+ { "so_broadcast", KW_SO_BROADCAST },
+@@ -229,7 +230,20 @@ static struct keyword keywords[] = {
+
+ #define MAX_REGEXP_LEN 1024
+
+-int linenum = 1;
++typedef struct _CfgIncludeLevel
++{
++ GSList *files;
++ gchar *current_file;
++ gint linenum;
++ struct yy_buffer_state *yybuf;
++} CfgIncludeLevel;
++
++#define MAX_INCLUDE_DEPTH 16
++
++static CfgIncludeLevel include_stack[MAX_INCLUDE_DEPTH];
++static gint include_depth = 0;
++
++
+ int lex_filter_params = 0;
+ char buf[MAX_REGEXP_LEN];
+ char *str;
+@@ -237,6 +251,7 @@ char *str;
+ static int check_reserved_words(char *token);
+ static void append_string(int length, char *str);
+ static void append_char(char c);
++static gboolean cfg_start_next_include(gboolean first_on_this_level);
+
+ %}
+
+@@ -254,9 +269,10 @@ word [^ \#'"\(\)\{\}\\;\n\t,|\.]
+ %%
-+facility_string
-+ : string { $$ = $1; };
-+ | KW_SYSLOG { $$ = strdup("syslog"); }
-+ ;
+ \#.*$ ;
+-\r?\n { linenum++; }
++\r?\n { include_stack[include_depth].linenum++; }
+ {white}+ ;
+ \.\. { return DOTDOT; }
++(-|\+)?{digit}+\.{digit}+ { yylval.fnum = strtod(yytext, NULL); return FLOAT; }
+ 0x{digit}+ { yylval.num = strtoll(yytext, NULL, 16); return NUMBER; }
+ 0{digit}+ { yylval.num = strtoll(yytext, NULL, 8); return NUMBER; }
+ (-|\+)?{digit}+ { yylval.num = strtoll(yytext, NULL, 10); return NUMBER; }
+@@ -298,16 +314,13 @@ word [^ \#'"\(\)\{\}\\;\n\t,|\.]
+ return STRING;
+ }
+
++
++<INITIAL><<EOF>> { if (!cfg_start_next_include(FALSE)) yyterminate(); }
+
%%
+-int
+-lex_init(FILE *file, gint init_line_num)
+-{
+- yyrestart(file);
+- linenum = init_line_num;
+- return 0;
+-}
+
+-int
++
++static int
+ check_reserved_words(char *token)
+ {
+ int i, j;
+@@ -339,6 +352,7 @@ check_reserved_words(char *token)
+ break;
+ }
+ keywords[i].kw_status = KWS_NORMAL;
++ yylval.token = keywords[i].kw_token;
+ return keywords[i].kw_token;
+ }
+ }
+@@ -364,3 +378,246 @@ append_char(char c)
+ str++;
+ *str = 0;
+ }
++
++const gchar *
++cfg_lex_get_current_file(void)
++{
++ CfgIncludeLevel *level = &include_stack[include_depth];
++
++ return level->current_file;
++}
++
++gint
++cfg_lex_get_current_lineno(void)
++{
++ CfgIncludeLevel *level = &include_stack[include_depth];
++
++ return level->linenum;
++}
++
++char *
++cfg_lex_get_keyword_string(int kw)
++{
++ int i;
++ for (i = 0; i < (sizeof(keywords) / sizeof(struct keyword)); i++)
++ {
++ if (keywords[i].kw_token == kw)
++ {
++ msg_warning("WARNING: Your configuration uses a newly introduced reserved word as identifier, please use a different name",
++ evt_tag_str("keyword", keywords[i].kw_name),
++ evt_tag_str("filename", cfg_lex_get_current_file()),
++ evt_tag_int("line", cfg_lex_get_current_lineno()),
++ NULL);
++ return strdup(keywords[i].kw_name);
++ }
++ }
++ g_assert_not_reached();
++}
++
++
++
++static gboolean
++cfg_start_next_include(gboolean first_on_this_level)
++{
++ FILE *include_file;
++ CfgIncludeLevel *level = &include_stack[include_depth];
++ gchar *filename;
++ struct yy_buffer_state *yybuf;
++
++ g_assert(level->yybuf == NULL);
++
++ if (include_depth == 0)
++ {
++ return FALSE;
++ }
++
++ if (!first_on_this_level)
++ {
++ msg_debug("Finishing include file",
++ evt_tag_str("filename", level->current_file),
++ evt_tag_int("depth", include_depth),
++ NULL);
++ }
++
++ if (!level->files)
++ {
++ yybuf = YY_CURRENT_BUFFER;
++ g_free(level->current_file);
++ level->current_file = NULL;
++ include_depth--;
++ yy_switch_to_buffer(include_stack[include_depth].yybuf);
++ include_stack[include_depth].yybuf = NULL;
++ if (!first_on_this_level)
++ yy_delete_buffer(yybuf);
++
++ return TRUE;
++ }
++
++ filename = (gchar *) level->files->data;
++ level->files = g_slist_delete_link(level->files, level->files);
++
++ include_file = fopen(filename, "r");
++ if (!include_file)
++ {
++ msg_error("Error opening include file",
++ evt_tag_str("filename", filename),
++ evt_tag_int("depth", include_depth),
++ NULL);
++ g_free(filename);
++ return FALSE;
++ }
++ msg_debug("Starting to read include file",
++ evt_tag_str("filename", filename),
++ evt_tag_int("depth", include_depth),
++ NULL);
++ if (level->current_file)
++ g_free(level->current_file);
++ level->current_file = filename;
++ level->linenum = 1;
++
++ yybuf = YY_CURRENT_BUFFER;
++ yy_switch_to_buffer(yy_create_buffer(include_file, YY_BUF_SIZE));
++ if (!first_on_this_level)
++ yy_delete_buffer(yybuf);
++ return TRUE;
++}
++
++gboolean
++cfg_lex_process_include(const gchar *filename)
++{
++ struct stat st;
++ gchar buf[1024];
++ CfgIncludeLevel *level;
++
++ if (include_depth >= MAX_INCLUDE_DEPTH - 1)
++ {
++ msg_error("Include file depth is too deep, increase MAX_INCLUDE_DEPTH and recompile",
++ evt_tag_str("filename", filename),
++ evt_tag_int("depth", include_depth),
++ NULL);
++ return FALSE;
++ }
++
++ if (filename[0] != '/')
++ {
++ g_snprintf(buf, sizeof(buf), "%s/%s", PATH_SYSCONFDIR, filename);
++ filename = buf;
++ }
++
++ if (stat(filename, &st) < 0)
++ {
++ msg_error("Include file/directory not found",
++ evt_tag_str("filename", filename),
++ evt_tag_errno("error", errno),
++ NULL);
++ return FALSE;
++ }
++ include_stack[include_depth].yybuf = YY_CURRENT_BUFFER;
++ include_depth++;
++ level = &include_stack[include_depth];
++ if (S_ISDIR(st.st_mode))
++ {
++ GDir *dir;
++ GError *error = NULL;
++ const gchar *entry;
++
++ dir = g_dir_open(filename, 0, &error);
++ if (!dir)
++ {
++ msg_error("Error opening directory for reading",
++ evt_tag_str("filename", filename),
++ evt_tag_str("error", error->message),
++ NULL);
++ goto drop_level;
++ }
++ while ((entry = g_dir_read_name(dir)))
++ {
++ const gchar *p;
++
++ for (p = entry; *p; p++)
++ {
++ if (!((*p >= 'a' && *p <= 'z') ||
++ (*p >= 'A' && *p <= 'Z') ||
++ (*p >= '0' && *p <= '9') ||
++ (*p == '_') || (*p == '-') || (*p == '.')))
++ {
++ msg_debug("Skipping include file, does not match pattern [\\-_a-zA-Z0-9]+",
++ evt_tag_str("filename", entry),
++ NULL);
++ p = NULL;
++ break;
++ }
++ }
++ if (p)
++ {
++ gchar *full_filename = g_build_filename(filename, entry, NULL);
++ if (stat(full_filename, &st) < 0 || S_ISDIR(st.st_mode))
++ {
++ msg_debug("Skipping include file as it is a directory",
++ evt_tag_str("filename", entry),
++ NULL);
++ g_free(full_filename);
++ continue;
++ }
++ level->files = g_slist_insert_sorted(level->files, full_filename, (GCompareFunc) strcmp);
++ msg_debug("Adding include file",
++ evt_tag_str("filename", entry),
++ NULL);
++ }
++ }
++ g_dir_close(dir);
++ if (!level->files)
++ {
++ /* no include files in the specified directory */
++ msg_debug("No files in this include directory",
++ evt_tag_str("dir", filename),
++ NULL);
++ include_depth--;
++ include_stack[include_depth].yybuf = NULL;
++ return TRUE;
++ }
++ }
++ else
++ {
++ g_assert(level->files == NULL);
++ level->files = g_slist_prepend(level->files, g_strdup(filename));
++ }
++ return cfg_start_next_include(TRUE);
++ drop_level:
++ g_slist_foreach(level->files, (GFunc) g_free, NULL);
++ g_slist_free(level->files);
++ level->files = NULL;
++ return FALSE;
++}
++
++int
++cfg_lex_init(FILE *file, gint init_line_num)
++{
++ CfgIncludeLevel *level;
++
++ yyrestart(file);
++ level = &include_stack[0];
++ level->current_file = g_strdup(configuration->filename);
++ level->linenum = init_line_num;
++ return 0;
++}
++
++void
++cfg_lex_deinit(void)
++{
++ gint i;
++
++ for (i = 0; i < include_depth; i++)
++ {
++ CfgIncludeLevel *level = &include_stack[i];
++
++ if (level->current_file)
++ g_free(level->current_file);
++
++ g_slist_foreach(level->files, (GFunc) g_free, NULL);
++ g_slist_free(level->files);
++ level->files = NULL;
++ if (level->yybuf)
++ yy_delete_buffer(level->yybuf);
++ }
++}
+diff --git a/src/cfg.c b/src/cfg.c
+index 23d93b6..45e5119 100644
+--- a/src/cfg.c
++++ b/src/cfg.c
+@@ -34,6 +34,8 @@
+ #include "logparser.h"
+ #include "serialize.h"
+
++#include <sys/types.h>
++#include <signal.h>
+ #include <stdio.h>
+ #include <string.h>
- extern int linenum;
-commit ef5eb95d26fcfe3746b78bba8d39cfa2cdb9eeeb
-Author: Balazs Scheidler <bazsi@balabit.hu>
-Date: Tue Dec 30 15:22:00 2008 +0100
-
- [LogReader] only assume that a file was moved if the size of the file is non-zero
-
- If an external logrotate program is used to rotate a logfile, a
- small race still exists when using syslog-ng to read that logfile,
- as described by Evan Rempel:
-
- "
- 1. Application is writing to log file named "A".
- 2. External log rotation renames "A" to "A.1"
- 3. External log rotation touches/creates file named "A" and sets appropriate
- permissions.
- 4. Internal timer of syslog-ng is triggered by follow_freq() setting. Syslog-ng will
- switch to the new file "A" because it exists, even though it was created only
- milliseconds earlier.
- 5. log rotation signals the application to switch log files (reload or restart).
- 6. Application flushes log buffers to current file which is now A.1, but syslog-ng
- is no longer reading this file.
- 7. Application closes current log file "A.1" and opens new log file "A".
-
- This sequence will result in the last buffer flush (step 6) from the application to
- be missed by syslog-ng.
- "
-
- This patch makes syslog-ng to switch to the new log file if it already
- received some data.
-
+@@ -203,15 +205,6 @@ cfg_deinit(GlobalConfig *cfg)
+ return log_center_deinit(cfg->center);
+ }
+
+-/* extern declarations in the generated parser & lexer */
+-extern FILE *yyin;
+-extern int yyparse();
+-extern void lex_init(FILE *, gint lineno);
+-extern int yydebug;
+-extern int linenum;
+-
+-extern void yyparser_reset(void);
+-
+ gboolean
+ cfg_read_pragmas(GlobalConfig *self, FILE *cfg, gint *lineno)
+ {
+@@ -358,8 +351,9 @@ cfg_new(gchar *fname)
+ self->chain_hostnames = TRUE;
+ }
+
+- lex_init(cfg, lineno);
++ cfg_lex_init(cfg, lineno);
+ res = yyparse();
++ cfg_lex_deinit();
+ fclose(cfg);
+ if (!res)
+ {
+@@ -481,7 +475,15 @@ cfg_reload_config(gchar *fname, GlobalConfig *cfg)
+ {
+ msg_error("Error initializing new configuration, reverting to old config", NULL);
+ cfg_persist_config_move(new_cfg, cfg);
+- cfg_init(cfg);
++ if (!cfg_init(cfg))
++ {
++ /* hmm. hmmm, error reinitializing old configuration, we're hosed.
++ * Best is to kill ourselves in the hope that the supervisor
++ * restarts us.
++ */
++ kill(getpid(), SIGQUIT);
++ g_assert_not_reached();
++ }
+ return cfg;
+ }
+ }
+diff --git a/src/cfg.h b/src/cfg.h
+index d7b4edc..91f3060 100644
+--- a/src/cfg.h
++++ b/src/cfg.h
+@@ -28,6 +28,7 @@
+
+ #include <sys/types.h>
+ #include <regex.h>
++#include <stdio.h>
+
+ struct _LogSourceGroup;
+ struct _LogDestGroup;
+@@ -148,6 +149,19 @@ void cfg_persist_set_version(GlobalConfig *cfg, const gint version);
+
+ void persist_config_free(PersistentConfig *persist);
+
++/* defined in the lexer */
++void yyerror(char *msg);
++int yylex();
++int cfg_lex_init(FILE *file, gint init_line_num);
++void cfg_lex_deinit(void);
++gboolean cfg_lex_process_include(const gchar *filename);
++const gchar *cfg_lex_get_current_file(void);
++gint cfg_lex_get_current_lineno(void);
++char *cfg_lex_get_keyword_string(int kw);
++
++/* defined in the parser */
++int yyparse(void);
++
+ static inline gboolean
+ cfg_check_current_config_version(gint req)
+ {
+diff --git a/src/filter.c b/src/filter.c
+index 0d1fe57..3a14fdd 100644
+--- a/src/filter.c
++++ b/src/filter.c
+@@ -375,6 +375,11 @@ filter_netmask_eval(FilterExprNode *s, LogMessage *msg)
+ {
+ addr.s_addr = htonl(INADDR_LOOPBACK);
+ }
++ else
++ {
++ /* no address information, return FALSE */
++ return s->comp;
++ }
+ return ((addr.s_addr & self->netmask.s_addr) == (self->address.s_addr)) ^ s->comp;
+
+ }
+diff --git a/src/gprocess.c b/src/gprocess.c
+index 5a4a76f..004f57c 100644
+--- a/src/gprocess.c
++++ b/src/gprocess.c
+@@ -87,7 +87,9 @@ static struct
+ GProcessMode mode;
+ const gchar *name;
+ const gchar *user;
++ uid_t uid;
+ const gchar *group;
++ gid_t gid;
+ const gchar *chroot_dir;
+ const gchar *pidfile;
+ const gchar *pidfile_dir;
+@@ -109,9 +111,15 @@ static struct
+ .argv = NULL,
+ .argv_start = NULL,
+ .argv_env_len = 0,
++#ifdef __CYGWIN__
++ .fd_limit_min = 256,
++#else
+ .fd_limit_min = 4096,
++#endif
+ .check_period = -1,
+ .check_fn = NULL,
++ .uid = -1,
++ .gid = -1
+ };
+
+ #if ENABLE_LINUX_CAPS
+@@ -255,6 +263,8 @@ g_process_set_user(const gchar *user)
+ {
+ if (!process_opts.user)
+ process_opts.user = user;
++
++
+ }
+
+ /**
+@@ -268,6 +278,7 @@ g_process_set_group(const gchar *group)
+ {
+ if (!process_opts.group)
+ process_opts.group = group;
++
+ }
+
+ /**
+@@ -666,35 +677,20 @@ g_process_change_root(void)
+ static gboolean
+ g_process_change_user(void)
+ {
+- uid_t uid = -1;
+- gid_t gid = -1;
+-
+ #if ENABLE_LINUX_CAPS
+ if (process_opts.caps)
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+ #endif
+
+- if (process_opts.user && !resolve_user(process_opts.user, &uid))
+- {
+- g_process_message("Error resolving user; user='%s'", process_opts.user);
+- return FALSE;
+- }
+-
+- if (process_opts.group && !resolve_group(process_opts.group, &gid))
+- {
+- g_process_message("Error resolving group; group='%s'", process_opts.group);
+- return FALSE;
+- }
+-
+- if ((gint) gid != -1)
++ if ((gint) process_opts.gid != -1)
+ {
+- if (setgid(gid) < 0)
++ if (setgid(process_opts.gid) < 0)
+ {
+- g_process_message("Error in setgid(); group='%s', error='%s'", process_opts.group, g_strerror(errno));
++ g_process_message("Error in setgid(); group='%s', gid='%d', error='%s'", process_opts.group, (gint) process_opts.gid, g_strerror(errno));
+ if (getuid() == 0)
+ return FALSE;
+ }
+- if (process_opts.user && initgroups(process_opts.user, gid) < 0)
++ if (process_opts.user && initgroups(process_opts.user, process_opts.gid) < 0)
+ {
+ g_process_message("Error in initgroups(); user='%s', error='%s'", process_opts.user, g_strerror(errno));
+ if (getuid() == 0)
+@@ -702,11 +698,11 @@ g_process_change_user(void)
+ }
+ }
+
+- if ((gint) uid != -1)
++ if ((gint) process_opts.uid != -1)
+ {
+- if (setuid(uid) < 0)
++ if (setuid(process_opts.uid) < 0)
+ {
+- g_process_message("Error in setuid(); user='%s', error='%s'", process_opts.user, g_strerror(errno));
++ g_process_message("Error in setuid(); user='%s', uid='%d', error='%s'", process_opts.user, (gint) process_opts.uid, g_strerror(errno));
+ if (getuid() == 0)
+ return FALSE;
+ }
+@@ -763,6 +759,21 @@ g_process_change_caps(void)
+
+ #endif
+
++static void
++g_process_resolve_names(void)
++{
++ if (process_opts.user && !resolve_user(process_opts.user, &process_opts.uid))
++ {
++ g_process_message("Error resolving user; user='%s'", process_opts.user);
++ process_opts.uid = (uid_t) -1;
++ }
++ if (process_opts.group && !resolve_group(process_opts.group, &process_opts.gid))
++ {
++ g_process_message("Error resolving group; group='%s'", process_opts.group);
++ process_opts.gid = (gid_t) -1;
++ }
++}
++
+ /**
+ * g_process_change_dir:
+ *
+@@ -1116,6 +1127,7 @@ g_process_start(void)
+
+ g_process_detach_tty();
+ g_process_change_limits();
++ g_process_resolve_names();
+
+ if (process_opts.mode == G_PM_BACKGROUND)
+ {
+diff --git a/src/logmsg.c b/src/logmsg.c
+index 9bad35f..d7f7558 100644
+--- a/src/logmsg.c
++++ b/src/logmsg.c
+@@ -264,6 +264,10 @@ log_msg_get_value(LogMessage *self, const gchar *value_name, gssize *length)
+ return value;
+ }
+
++/**
++ * NOTE: the new_value is taken as a reference, e.g. it'll be assigned to
++ * the LogMessage and freed later on.
++ **/
+ void
+ log_msg_set_value(LogMessage *self, const gchar *value_name, gchar *new_value, gssize length)
+ {
+@@ -1065,7 +1069,7 @@ log_msg_parse_version(LogMessage *self, const guchar **data, gint *length)
+ }
+
+ static void
+-log_msg_parse_legacy_program_name(LogMessage *self, const guchar **data, gint *length)
++log_msg_parse_legacy_program_name(LogMessage *self, const guchar **data, gint *length, guint flags)
+ {
+ /* the data pointer will not change */
+ const guchar *src, *prog_start;
+@@ -1110,6 +1114,11 @@ log_msg_parse_legacy_program_name(LogMessage *self, const guchar **data, gint *l
+ src++;
+ left--;
+ }
++ if (flags & LP_STORE_LEGACY_MSGHDR)
++ {
++ log_msg_set_value(self, "LEGACY_MSGHDR", g_strndup((gchar *) *data, *length - left), *length - left);
++ self->flags |= LF_LEGACY_MSGHDR;
++ }
+ *data = src;
+ *length = left;
+ }
+@@ -1573,7 +1582,7 @@ log_msg_parse_legacy(LogMessage *self, const guchar *data, gint length, guint fl
+ log_msg_parse_skip_chars(self, &src, &left, " ", -1);
+
+ /* Try to extract a program name */
+- log_msg_parse_legacy_program_name(self, &src, &left);
++ log_msg_parse_legacy_program_name(self, &src, &left, flags);
+ }
+
+ /* If we did manage to find a hostname, store it. */
+@@ -1598,7 +1607,7 @@ log_msg_parse_legacy(LogMessage *self, const guchar *data, gint length, guint fl
+ else
+ {
+ /* Capture the program name */
+- log_msg_parse_legacy_program_name(self, &src, &left);
++ log_msg_parse_legacy_program_name(self, &src, &left, flags);
+ }
+ self->timestamps[LM_TS_STAMP] = self->timestamps[LM_TS_RECVD];
+ }
+@@ -1607,7 +1616,7 @@ log_msg_parse_legacy(LogMessage *self, const guchar *data, gint length, guint fl
+ self->message_len = left;
+ if ((flags & LP_VALIDATE_UTF8) && g_utf8_validate((gchar *) src, left, NULL))
+ self->flags |= LF_UTF8;
+-
++
+ return TRUE;
+ }
+
+diff --git a/src/logmsg.h b/src/logmsg.h
+index 17d4b5c..6e0a9be 100644
+--- a/src/logmsg.h
++++ b/src/logmsg.h
+@@ -47,6 +47,7 @@
+ #define LP_ASSUME_UTF8 0x0080
+ #define LP_VALIDATE_UTF8 0x0100
+ #define LP_NO_MULTI_LINE 0x0200
++#define LP_STORE_LEGACY_MSGHDR 0x0400
+
+
+ typedef struct _LogPathOptions LogPathOptions;
+@@ -97,6 +98,13 @@ enum
+ LF_OWN_MATCHES = 0x4000,
+ LF_OWN_ALL = 0x7FF0,
+ LF_CHAINED_HOSTNAME = 0x8000,
++
++ /* originally parsed from RFC 3164 format and the legacy message header
++ * was saved in $LEGACY_MSGHDR. This flag is a hack to avoid a hash lookup
++ * in the fast path and indicates that the parser has saved the legacy
++ * message header intact in a value named LEGACY_MSGHDR.
++ */
++ LF_LEGACY_MSGHDR = 0x00010000,
+ };
+
+ typedef struct _LogMessageSDParam LogMessageSDParam;
+@@ -129,12 +137,25 @@ typedef struct _LogMessageMatch
+ guint16 ofs;
+ guint16 len;
+ #else
++
++#if GLIB_SIZEOF_VOID_P == 4
++ guint16 ofs;
++ guint8 __pad;
++ guint8 flags;
++ guint16 len;
++ guint8 builtin_value;
++ guint8 type;
++#elif GLIB_SIZEOF_VOID_P == 8
+ guint16 ofs;
+ guint16 len;
+ guint8 builtin_value;
+ guint8 type;
+ guint8 __pad;
+ guint8 flags;
++#else
++#error "Unknown pointer size"
++#endif
++
+ #endif
+ };
+ };
+@@ -156,9 +177,10 @@ struct _LogMessage
+ */
+ struct
+ {
+- guint16 flags;
+- guint16 pri;
++ guint32 flags;
+ guint32 message_len;
++ guint16 pri;
++ /* 6 bytes hole */
+
+ LogStamp timestamps[LM_TS_MAX];
+ gchar * const host;
+diff --git a/src/logproto.c b/src/logproto.c
+index b2c30ee..9d7187b 100644
+--- a/src/logproto.c
++++ b/src/logproto.c
+@@ -8,11 +8,22 @@
+ gboolean
+ log_proto_set_encoding(LogProto *self, const gchar *encoding)
+ {
+- self->convert = g_iconv_open("utf-8", encoding);
+ if (self->convert != (GIConv) -1)
+ {
+- return FALSE;
++ g_iconv_close(self->convert);
++ self->convert = (GIConv) -1;
++ }
++ if (self->encoding)
++ {
++ g_free(self->encoding);
++ self->encoding = NULL;
+ }
++
++ self->convert = g_iconv_open("utf-8", encoding);
++ if (self->convert == (GIConv) -1)
++ return FALSE;
++
++ self->encoding = g_strdup(encoding);
+ return TRUE;
+ }
+
+@@ -23,6 +34,8 @@ log_proto_free(LogProto *s)
+ s->free_fn(s);
+ if (s->convert != (GIConv) -1)
+ g_iconv_close(s->convert);
++ if (s->encoding)
++ g_free(s->encoding);
+ log_transport_free(s->transport);
+ g_free(s);
+ }
+@@ -159,6 +172,8 @@ struct _LogProtoPlainServer
+ gsize buffer_size, buffer_end, buffer_pos;
+ gsize padding_size, max_msg_size;
+ GSockAddr *prev_saddr;
++ gchar raw_buffer_leftover[8];
++ gint raw_buffer_leftover_size;
+ LogProtoStatus status;
+ };
+
+@@ -487,7 +502,8 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS
+ /* if conversion is needed, we first read into an on-stack
+ * buffer, and then convert it into our internal buffer */
+
+- raw_buffer = g_alloca(self->max_msg_size);
++ raw_buffer = g_alloca(self->max_msg_size + self->raw_buffer_leftover_size);
++ memcpy(raw_buffer, self->raw_buffer_leftover, self->raw_buffer_leftover_size);
+ if (!self->padding_size)
+ {
+ avail = self->max_msg_size;
+@@ -499,7 +515,7 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS
+ }
+ }
+
+- rc = log_transport_read(self->super.transport, raw_buffer, avail, sa);
++ rc = log_transport_read(self->super.transport, raw_buffer + self->raw_buffer_leftover_size, avail, sa);
+ if (sa && *sa)
+ self->prev_saddr = *sa;
+ if (rc < 0)
+@@ -534,6 +550,13 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS
+ msg_verbose("EOF occurred while reading",
+ evt_tag_int(EVT_TAG_FD, self->super.transport->fd),
+ NULL);
++ if (self->raw_buffer_leftover_size > 0)
++ {
++ msg_error("EOF read on a channel with leftovers from previous character conversion, dropping input",
++ NULL);
++ self->status = LPS_EOF;
++ return self->status;
++ }
+ self->status = LPS_EOF;
+ if (log_proto_plain_server_fetch_from_buf(self, msg, msg_len, TRUE))
+ {
+@@ -562,6 +585,9 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS
+ }
+ else
+ {
++ rc += self->raw_buffer_leftover_size;
++ self->raw_buffer_leftover_size = 0;
++
+ /* some data was read */
+ if (self->super.convert != (GIConv) -1)
+ {
+@@ -581,22 +607,62 @@ log_proto_plain_server_fetch(LogProto *s, const guchar **msg, gsize *msg_len, GS
+ switch (errno)
+ {
+ case EINVAL:
+- /* Incomplete text, do not report an error */
++ /* Incomplete text, do not report an error, rather try to read again */
++ self->buffer_end = self->buffer_size - avail_out;
++
++ if (avail_in > 0)
++ {
++ if (avail_in > sizeof(self->raw_buffer_leftover))
++ {
++ msg_error("Invalid byte sequence, the remaining raw buffer is larger than the supported leftover size",
++ evt_tag_str("encoding", self->super.encoding),
++ evt_tag_int("avail_in", avail_in),
++ evt_tag_int("leftover_size", sizeof(self->raw_buffer_leftover)),
++ NULL);
++ self->status = LPS_ERROR;
++ return self->status;
++ }
++ memcpy(self->raw_buffer_leftover, raw_buffer, avail_in);
++ self->raw_buffer_leftover_size = avail_in;
++ msg_debug("Leftover characters remained after conversion, delaying message until another chunk arrives",
++ evt_tag_str("encoding", self->super.encoding),
++ evt_tag_int("avail_in", avail_in),
++ NULL);
++ return LPS_SUCCESS;
++ }
+ break;
+ case E2BIG:
+
+ self->buffer_end = self->buffer_size - avail_out;
+ /* extend the buffer */
+- self->buffer_size *= 2;
+- self->buffer = g_realloc(self->buffer, self->buffer_size);
+
+- /* recalculate the out pointer, and add what we have now */
+- ret = -1;
++ if (self->buffer_size < self->max_msg_size * 6)
++ {
++ self->buffer_size *= 2;
++ self->buffer = g_realloc(self->buffer, self->buffer_size);
++
++ /* recalculate the out pointer, and add what we have now */
++ ret = -1;
++ }
++ else
++ {
++ msg_error("Incoming byte stream requires a too large conversion buffer, probably invalid character sequence",
++ evt_tag_str("encoding", self->super.encoding),
++ evt_tag_printf("buffer", "%.*s", self->buffer_end, self->buffer),
++ NULL);
++ self->status = LPS_ERROR;
++ return self->status;
++ }
+ break;
+ case EILSEQ:
+ default:
+- msg_error("Invalid byte sequence or other error while converting input",
+- NULL);
++ msg_notice("Invalid byte sequence or other error while converting input, skipping character",
++ evt_tag_str("encoding", self->super.encoding),
++ evt_tag_printf("char", "0x%02x", *(guchar *) raw_buffer),
++ NULL);
++ self->buffer_end = self->buffer_size - avail_out;
++ raw_buffer++;
++ avail_in--;
+ break;
+ }
+ }
+diff --git a/src/logproto.h b/src/logproto.h
+index 8a03d75..f94e5df 100644
+--- a/src/logproto.h
++++ b/src/logproto.h
+@@ -18,6 +18,7 @@ struct _LogProto
+ {
+ LogTransport *transport;
+ GIConv convert;
++ gchar *encoding;
+ guint flags;
+ gboolean (*read_state)(LogProto *s, SerializeArchive *archive);
+ gboolean (*write_state)(LogProto *s, SerializeArchive *archive);
diff --git a/src/logreader.c b/src/logreader.c
-index f9567ff..40e2ae7 100644
+index f9567ff..ca800d0 100644
--- a/src/logreader.c
+++ b/src/logreader.c
+@@ -103,7 +103,7 @@ log_reader_fd_prepare(GSource *source,
+
+ if (self->reader->flags & LR_FOLLOW)
+ {
+- *timeout = self->reader->options->follow_freq * 1000;
++ *timeout = self->reader->options->follow_freq;
+ return FALSE;
+ }
+
@@ -167,7 +167,7 @@ log_reader_fd_check(GSource *source)
if (self->reader->follow_filename && stat(self->reader->follow_filename, &followed_st) != -1)
{
- if (fd < 0 || st.st_ino != followed_st.st_ino)
-+ if (fd < 0 || (st.st_ino != followed_st.st_ino && st.st_size > 0))
++ if (fd < 0 || (st.st_ino != followed_st.st_ino && followed_st.st_size > 0))
{
msg_trace("log_reader_fd_check file moved eof",
evt_tag_int("pos", pos),
-commit 8ad0edb1e4198bbf657708d07360bbac8b30b55a
-Author: Balazs Scheidler <bazsi@balabit.hu>
-Date: Thu Feb 5 11:26:18 2009 +0100
-
- [affile] validate file type before opening
-
- report an error if a file is opened using the pipe() driver, OR a
- fifo is opened using the file() driver. named pipes should really be
- driven by the pipe() driver.
-
-diff --git a/src/affile.c b/src/affile.c
-index f9264a7..e582a5d 100644
---- a/src/affile.c
-+++ b/src/affile.c
-@@ -45,6 +45,7 @@ affile_open_file(gchar *name, gint flags,
- gboolean create_dirs, gboolean privileged, gboolean is_pipe, gint *fd)
- {
- cap_t saved_caps;
-+ struct stat st;
+@@ -278,6 +278,8 @@ log_reader_fetch_log(LogReader *self, LogProto *proto)
+ parse_flags |= LP_VALIDATE_UTF8;
+ if (self->options->options & LRO_NO_MULTI_LINE)
+ parse_flags |= LP_NO_MULTI_LINE;
++ if (self->options->options & LRO_STORE_LEGACY_MSGHDR)
++ parse_flags |= LP_STORE_LEGACY_MSGHDR;
+
+ if (self->waiting_for_preemption)
+ may_read = FALSE;
+@@ -321,7 +323,7 @@ log_reader_fetch_log(LogReader *self, LogProto *proto)
+ /* no more messages for now */
+ break;
+ }
+- if (msg_len > 0)
++ if (msg_len > 0 || (self->options->options & LRO_EMPTY_LINES))
+ {
+ msg_count++;
- if (strstr(name, "../") || strstr(name, "/.."))
+@@ -772,6 +774,10 @@ log_reader_options_lookup_flag(const gchar *flag)
+ return LRO_VALIDATE_UTF8;
+ if (strcmp(flag, "no-multi-line") == 0 || strcmp(flag, "no_multi_line") == 0)
+ return LRO_NO_MULTI_LINE;
++ if (strcmp(flag, "store-legacy-msghdr") == 0 || strcmp(flag, "store_legacy_msghdr") == 0)
++ return LRO_STORE_LEGACY_MSGHDR;
++ if (strcmp(flag, "empty-lines") == 0 || strcmp(flag, "empty_lines") == 0)
++ return LRO_EMPTY_LINES;
+ msg_error("Unknown parse flag", evt_tag_str("flag", flag), NULL);
+ return 0;
+ }
+diff --git a/src/logreader.h b/src/logreader.h
+index 8e5bc7c..11ff0da 100644
+--- a/src/logreader.h
++++ b/src/logreader.h
+@@ -43,6 +43,8 @@
+ #define LRO_SYSLOG_PROTOCOL 0x0004
+ #define LRO_VALIDATE_UTF8 0x0008
+ #define LRO_NO_MULTI_LINE 0x0010
++#define LRO_STORE_LEGACY_MSGHDR 0x0020
++#define LRO_EMPTY_LINES 0x0040
+
+ typedef struct _LogReaderWatch LogReaderWatch;
+
+@@ -77,7 +79,7 @@ typedef struct _LogReader
+ GSockAddr *peer_addr;
+ gchar *follow_filename;
+ ino_t inode;
+- off_t size;
++ gint64 size;
+
+ } LogReader;
+
+@@ -86,7 +88,7 @@ void log_reader_set_follow_filename(LogPipe *self, const gchar *follow_filename)
+ void log_reader_set_peer_addr(LogPipe *s, GSockAddr *peer_addr);
+ void log_reader_set_immediate_check(LogPipe *s);
+
+-void log_reader_update_pos(LogReader *self, off_t ofs);
++void log_reader_update_pos(LogReader *self, gint64 ofs);
+ void log_reader_save_state(LogReader *self, SerializeArchive *archive);
+ void log_reader_restore_state(LogReader *self, SerializeArchive *archive);
+
+diff --git a/src/logwriter.c b/src/logwriter.c
+index bb01148..5f77293 100644
+--- a/src/logwriter.c
++++ b/src/logwriter.c
+@@ -595,9 +595,20 @@ log_writer_format_log(LogWriter *self, LogMessage *lm, GString *result)
+ g_string_append_len(result, lm->host, lm->host_len);
+ g_string_append_c(result, ' ');
+
+- g_string_append_len(result, lm->program, lm->program_len);
+- if (lm->program_len > 0)
++ if ((lm->flags & LF_LEGACY_MSGHDR))
+ {
++ gssize length;
++ const gchar *msghdr;
++
++ msghdr = log_msg_get_value(lm, "LEGACY_MSGHDR", &length);
++ if (msghdr)
++ {
++ g_string_append_len(result, msghdr, length);
++ }
++ }
++ else if (lm->program_len > 0)
++ {
++ g_string_append_len(result, lm->program, lm->program_len);
+ if (lm->pid_len > 0)
+ {
+ g_string_append_c(result, '[');
+diff --git a/src/main.c b/src/main.c
+index ba97f0c..f78dcc1 100644
+--- a/src/main.c
++++ b/src/main.c
+@@ -366,8 +366,6 @@ main(int argc, char *argv[])
+
+ g_process_set_name("syslog-ng");
+
+-#if ENABLE_LINUX_CAPS
+-
+ /* in this case we switch users early while retaining a limited set of
+ * credentials in order to initialize/reinitialize the configuration.
+ */
+@@ -381,27 +379,11 @@ main(int argc, char *argv[])
+ }
+ else
{
-@@ -63,6 +64,23 @@ affile_open_file(gchar *name, gint flags,
- g_process_cap_modify(CAP_DAC_READ_SEARCH, TRUE);
- g_process_cap_modify(CAP_SYS_ADMIN, TRUE);
+- g_process_startup_ok();
++ if (syntax_only)
++ g_process_startup_failed(0, TRUE);
++ else
++ g_process_startup_ok();
}
-+ if (stat(name, &st) >= 0)
+-#else
+-
+- /* if Linux capabilities are not compiled in, the initial setup is
+- * performed as the root user, and then the switch to a limited user
+- * account is made. This is compatible how syslog-ng behaved before
+- * capability support.
+- */
+-
+- rc = initial_init(&cfg);
+- if (rc)
+- {
+- return rc;
+- }
+- g_process_start();
+- g_process_startup_ok();
+-#endif
+-
+- if (syntax_only)
+- return 0;
+
+ /* we are running as a non-root user from this point */
+
+@@ -424,6 +406,7 @@ main(int argc, char *argv[])
+ app_shutdown();
+ tls_deinit();
+ z_mem_trace_dump();
++ g_process_finish();
+ return rc;
+ }
+
+diff --git a/src/memtrace.c b/src/memtrace.c
+index ef4729a..eb33f4f 100644
+--- a/src/memtrace.c
++++ b/src/memtrace.c
+@@ -121,7 +121,7 @@ z_mem_trace_init(gchar *tracefile)
+ for (i = 0; i < MEMTRACE_HASH_SIZE; i++)
+ {
+ mem_trace_hash[i].list = -1;
+- memset(&mem_trace_hash[i].lock, 0, sizeof(GStaticMutex));
++ g_static_mutex_init(&mem_trace_hash[i].lock);
+ }
+ old_malloc = dlsym(RTLD_NEXT, "malloc");
+ old_free = dlsym(RTLD_NEXT, "free");
+diff --git a/src/misc.c b/src/misc.c
+index 96fcdd2..364ead6 100644
+--- a/src/misc.c
++++ b/src/misc.c
+@@ -274,7 +274,7 @@ resolve_user(const char *user, uid_t *uid)
+ struct passwd *pw;
+
+ *uid = 0;
+- if (*user)
++ if (!(*user))
+ return FALSE;
+
+ pw = getpwnam(user);
+@@ -299,7 +299,7 @@ resolve_group(const char *group, gid_t *gid)
+ struct group *gr;
+
+ *gid = 0;
+- if (!*group)
++ if (!(*group))
+ return FALSE;
+
+ gr = getgrnam(group);
+diff --git a/src/sgroup.c b/src/sgroup.c
+index add7ac9..27e863f 100644
+--- a/src/sgroup.c
++++ b/src/sgroup.c
+@@ -25,8 +25,10 @@
+ #include "misc.h"
+ #include "messages.h"
+ #include "stats.h"
++#include "afinter.h"
+
+ #include <time.h>
++#include <string.h>
+
+ static gboolean
+ log_source_group_init(LogPipe *s)
+diff --git a/src/templates.c b/src/templates.c
+index aee1f34..67b8217 100644
+--- a/src/templates.c
++++ b/src/templates.c
+@@ -339,17 +339,33 @@ log_macro_expand(GString *result, gint id, guint32 flags, gint ts_format, TimeZo
+ }
+ break;
+ case M_MSGHDR:
+- /* message, complete with program name and pid */
+- result_append(result, msg->program, msg->program_len, !!(flags & LT_ESCAPE));
+- if (msg->program_len > 0)
++ if ((msg->flags & LF_LEGACY_MSGHDR))
+ {
+- if (msg->pid_len > 0)
++ gssize length;
++ const gchar *msghdr;
++
++ /* fast path for now, as most messages come from legacy devices */
++
++ msghdr = log_msg_get_value(msg, "LEGACY_MSGHDR", &length);
++ if (msghdr)
+ {
+- result_append(result, "[", 1, !!(flags & LT_ESCAPE));
+- result_append(result, msg->pid, msg->pid_len, !!(flags & LT_ESCAPE));
+- result_append(result, "]", 1, !!(flags & LT_ESCAPE));
++ result_append(result, msghdr, length, !!(flags & LT_ESCAPE));
++ }
++ }
++ else
++ {
++ /* message, complete with program name and pid */
++ result_append(result, msg->program, msg->program_len, !!(flags & LT_ESCAPE));
++ if (msg->program_len > 0)
++ {
++ if (msg->pid_len > 0)
++ {
++ result_append(result, "[", 1, !!(flags & LT_ESCAPE));
++ result_append(result, msg->pid, msg->pid_len, !!(flags & LT_ESCAPE));
++ result_append(result, "]", 1, !!(flags & LT_ESCAPE));
++ }
++ result_append(result, ": ", 2, !!(flags & LT_ESCAPE));
+ }
+- result_append(result, ": ", 2, !!(flags & LT_ESCAPE));
+ }
+ break;
+ case M_MESSAGE:
+@@ -433,6 +449,9 @@ log_macro_expand(GString *result, gint id, guint32 flags, gint ts_format, TimeZo
+ * local timezone
+ */
+ zone_ofs = (zone_info != NULL ? time_zone_info_get_offset(zone_info, stamp->time.tv_sec) : stamp->zone_offset);
++ if (zone_ofs == -1)
++ zone_ofs = stamp->zone_offset;
++
+ t = stamp->time.tv_sec + zone_ofs;
+ tm = gmtime_r(&t, &tm_storage);
+
+@@ -506,9 +525,6 @@ log_macro_expand(GString *result, gint id, guint32 flags, gint ts_format, TimeZo
+ }
+ break;
+ }
+-
+-
+-
+ g_assert_not_reached();
+ break;
+ }
+@@ -634,6 +650,9 @@ log_template_compile(LogTemplate *self, GError **error)
+
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
++ if (self->compiled_template)
++ return TRUE;
++
+ p = self->template;
+
+ while (*p)
+@@ -754,7 +773,7 @@ log_template_append_format(LogTemplate *self, LogMessage *lm, guint flags, gint
+
+ flags |= self->flags;
+
+- if (self->compiled_template == NULL && !log_template_compile(self, NULL))
++ if (!log_template_compile(self, NULL))
+ return;
+
+ for (p = self->compiled_template; p; p = g_list_next(p))
+diff --git a/src/tlscontext.c b/src/tlscontext.c
+index b22b546..c06ec88 100644
+--- a/src/tlscontext.c
++++ b/src/tlscontext.c
+@@ -102,28 +102,41 @@ tls_session_verify_dn(X509_STORE_CTX *ctx)
+ }
+
+ int
+-tls_session_verify(int ok, X509_STORE_CTX *ctx)
++tls_session_verify(TLSSession *self, int ok, X509_STORE_CTX *ctx)
+ {
++ /* untrusted means that we have to accept the certificate even if it is untrusted */
++ if (self->ctx->verify_mode & TVM_UNTRUSTED)
++ return 1;
++
++ /* accept certificate if its fingerprint matches, again regardless whether x509 certificate validation was successful */
+ if (tls_session_verify_fingerprint(ctx))
+- return 1; /* success */
+ {
-+ if (is_pipe && !S_ISFIFO(st.st_mode))
++ msg_debug("Certificate accepted because its fingerprint is listed", NULL);
++ return 1;
++ }
++
++ if (ok && ctx->error_depth != 0 && (ctx->current_cert->ex_flags & EXFLAG_CA) == 0)
++ {
++ msg_debug("Invalid certificate found in chain, basicConstraints.ca is unset in non-leaf certificate", NULL);
++ ctx->error = X509_V_ERR_INVALID_CA;
++ return 0;
++ }
+
++ /* reject certificate if it is valid, but its DN is not trusted */
+ if (ok && ctx->error_depth == 0 && !tls_session_verify_dn(ctx))
+ {
++ msg_debug("Certificate valid, but DN constraints were not met, rejecting", NULL);
+ ctx->error = X509_V_ERR_CERT_UNTRUSTED;
+- return 0; /* fail */
++ return 0;
+ }
+-
+- return ok;
+-}
+-
+-int
+-tls_session_ignore_errors(int ok, X509_STORE_CTX *ctx)
+-{
+ /* if the crl_dir is set in the configuration file but the directory is empty ignore this error */
+- if (ok == 0 && ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL)
+- return 1;
+- else
+- return ok;
++ if (!ok && ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL)
++ {
++ msg_notice("CRL directory is set but no CRLs found", NULL);
++ return 1;
++ }
++
++ return ok;
+ }
+
+ int
+@@ -132,10 +145,8 @@ tls_session_verify_callback(int ok, X509_STORE_CTX *ctx)
+ SSL *ssl = X509_STORE_CTX_get_app_data(ctx);
+ TLSSession *self = SSL_get_app_data(ssl);
+
+- ok = tls_session_verify(ok, ctx);
++ ok = tls_session_verify(self, ok, ctx);
+
+- ok = tls_session_ignore_errors(ok, ctx);
+-
+ tls_log_certificate_validation_progress(ok, ctx);
+
+ if (self->verify_func)
+@@ -165,9 +176,6 @@ tls_session_set_verify(TLSSession *self, TLSSessionVerifyFunc verify_func, gpoin
+ self->verify_func = verify_func;
+ self->verify_data = verify_data;
+ self->verify_data_destroy = verify_destroy;
+-
+- SSL_set_app_data(self->ssl, self);
+- SSL_set_verify(self->ssl, SSL_get_verify_mode(self->ssl), tls_session_verify_callback);
+ }
+
+ static TLSSession *
+@@ -212,11 +220,13 @@ TLSSession *
+ tls_context_setup_session(TLSContext *self)
+ {
+ SSL *ssl;
++ TLSSession *session;
+ gint ssl_error;
+
+ if (!self->ssl_ctx)
+ {
+ gint verify_mode = 0;
++ gint verify_flags = X509_V_FLAG_POLICY_CHECK;
+
+ if (self->mode == TM_CLIENT)
+ self->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+@@ -240,7 +250,9 @@ tls_context_setup_session(TLSContext *self)
+ goto error;
+
+ if (self->crl_dir)
+- X509_VERIFY_PARAM_set_flags(self->ssl_ctx->param, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
++ verify_flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL;
++
++ X509_VERIFY_PARAM_set_flags(self->ssl_ctx->param, verify_flags);
+
+ switch (self->verify_mode)
+ {
+@@ -254,7 +266,7 @@ tls_context_setup_session(TLSContext *self)
+ verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
+ break;
+ case TVM_REQUIRED | TVM_UNTRUSTED:
+- verify_mode = SSL_VERIFY_NONE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
++ verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ break;
+ case TVM_REQUIRED | TVM_TRUSTED:
+ verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+@@ -263,7 +275,7 @@ tls_context_setup_session(TLSContext *self)
+ g_assert_not_reached();
+ }
+
+- SSL_CTX_set_verify(self->ssl_ctx, verify_mode, NULL);
++ SSL_CTX_set_verify(self->ssl_ctx, verify_mode, tls_session_verify_callback);
+ SSL_CTX_set_options(self->ssl_ctx, SSL_OP_NO_SSLv2);
+ }
+
+@@ -273,7 +285,10 @@ tls_context_setup_session(TLSContext *self)
+ SSL_set_connect_state(ssl);
+ else
+ SSL_set_accept_state(ssl);
+- return tls_session_new(ssl, self);
++
++ session = tls_session_new(ssl, self);
++ SSL_set_app_data(ssl, session);
++ return session;
+
+ error:
+ ssl_error = ERR_get_error();
+diff --git a/src/tlscontext.h b/src/tlscontext.h
+index ada8e18..568682d 100644
+--- a/src/tlscontext.h
++++ b/src/tlscontext.h
+@@ -7,7 +7,7 @@
+
+ #include "syslog-ng.h"
+
+-#ifdef ENABLE_SSL
++#if ENABLE_SSL
+
+ #include <openssl/ssl.h>
+
+@@ -69,6 +69,9 @@ gboolean tls_verify_certificate_name(X509 *cert, const gchar *hostname);
+
+ #else
+
++typedef struct _TLSContext TLSContext;
++typedef struct _TLSSession TLSSession;
++
+ #define tls_context_new(m)
+
+ #endif
+diff --git a/src/tlstransport.c b/src/tlstransport.c
+index 608a427..2f07625 100644
+--- a/src/tlstransport.c
++++ b/src/tlstransport.c
+@@ -1,5 +1,7 @@
+ #include "tlstransport.h"
+
++#if ENABLE_SSL
++
+ #include "messages.h"
+
+ #include <openssl/ssl.h>
+@@ -149,4 +151,4 @@ log_transport_tls_free_method(LogTransport *s)
+ log_transport_free_method(s);
+ }
+
+-
++#endif
+diff --git a/tests/functional/func_test.py b/tests/functional/func_test.py
+index d7af8ff..ffd0fae 100755
+--- a/tests/functional/func_test.py
++++ b/tests/functional/func_test.py
+@@ -2,6 +2,7 @@
+
+ import os, sys, signal, traceback, time, errno
+ from socket import *
++import struct
+
+ padding = 'x' * 250
+ session_counter = 0
+@@ -39,12 +40,24 @@ class SocketSender(MessageSender):
+ self.sock = socket(self.family, SOCK_STREAM)
+
+ self.sock.connect(self.sock_name)
++ self.sock.setsockopt(SOL_SOCKET, SO_SNDTIMEO, struct.pack('ll', 3, 0))
++ if self.dgram:
++ self.sock.send('')
+
+ def sendMessage(self, msg):
+ line = '%s%s' % (msg, self.terminate_seq)
+ if self.send_by_bytes:
+ for c in line:
+- self.sock.send(c)
++ try:
++ self.sock.send(c)
++ except error, e:
++ if e[0] == errno.ENOBUFS:
++ print 'got ENOBUFS, sleeping...'
++ time.sleep(0.5)
++ repeat = True
++ else:
++ print "hmm... got an error to the 'send' call, maybe syslog-ng is not accepting messages?"
++ raise
+ else:
+ repeat = True
+ while repeat:
+@@ -59,6 +72,9 @@ class SocketSender(MessageSender):
+ print 'got ENOBUFS, sleeping...'
+ time.sleep(0.5)
+ repeat = True
++ else:
++ print "hmm... got an error to the 'send' call, maybe syslog-ng is not accepting messages?"
++ raise
+
+ def __str__(self):
+ if self.family == AF_UNIX:
+diff --git a/tests/unit/test_logqueue.c b/tests/unit/test_logqueue.c
+index 6e9dd00..b27f08e 100644
+--- a/tests/unit/test_logqueue.c
++++ b/tests/unit/test_logqueue.c
+@@ -115,6 +115,91 @@ testcase_zero_diskbuf_alternating_send_acks()
+ log_queue_free(q);
+ }
+
++#if 0
++
++/* no synchronization between the feed/consume threads, therefore it does
++ * not succeed reliably. commented out for now, will fix at the next
++ * logqueue related threaded issue */
++
++GStaticMutex threaded_lock = G_STATIC_MUTEX_INIT;
++
++gpointer
++threaded_feed(gpointer st)
++{
++ LogQueue *q = (LogQueue *) st;
++ char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép";
++ gint i;
++ LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
++ LogMessage *msg;
++
++ for (i = 0; i < 100000; i++)
++ {
++ msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), 0, NULL, -1);
++ log_msg_add_ack(msg, &path_options);
++ msg->ack_func = test_ack;
++
++ g_static_mutex_lock(&threaded_lock);
++ if (!log_queue_push_tail(q, msg, &path_options))
+ {
-+ msg_error("Error opening pipe, underlying file is not a FIFO, it should be used by file()",
-+ evt_tag_str("filename", name),
-+ NULL);
-+ goto exit;
++ fprintf(stderr, "Queue unable to consume enough messages: %d\n", fed_messages);
++ return GUINT_TO_POINTER(1);
+ }
-+ else if (!is_pipe && S_ISFIFO(st.st_mode))
++ g_static_mutex_unlock(&threaded_lock);
++ }
++ return NULL;
++}
++
++gpointer
++threaded_consume(gpointer st)
++{
++ LogQueue *q = (LogQueue *) st;
++ LogMessage *msg;
++ LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
++ gboolean success;
++ gint i;
++
++ for (i = 0; i < 100000; i++)
++ {
++ g_static_mutex_lock(&threaded_lock);
++ msg = NULL;
++ success = log_queue_pop_head(q, &msg, &path_options, FALSE);
++ g_static_mutex_unlock(&threaded_lock);
++
++ g_assert(!success || (success && msg != NULL));
++ if (!success)
+ {
-+ msg_error("Error opening file, underlying file is a FIFO, it should be used by pipe()",
-+ evt_tag_str("filename", name),
-+ NULL);
-+ goto exit;
++ fprintf(stderr, "Queue didn't return enough messages: i=%d\n", i);
++ return GUINT_TO_POINTER(1);
+ }
++
++ log_msg_ack(msg, &path_options);
++ log_msg_unref(msg);
+ }
- *fd = open(name, flags, mode);
- if (is_pipe && *fd < 0 && errno == ENOENT)
- {
-@@ -82,6 +100,7 @@ affile_open_file(gchar *name, gint flags,
- if (mode != -1)
- fchmod(*fd, mode);
- }
-+ exit:
- if (privileged)
++
++ return NULL;
++}
++
++void
++testcase_with_threads()
++{
++ LogQueue *q;
++ GThread *thread_feed, *thread_consume;
++ gint i;
++
++ for (i = 0; i < 100; i++)
++ {
++ q = log_queue_new(100000, 0, 64);
++ thread_feed = g_thread_create(threaded_feed, q, TRUE, NULL);
++
++ thread_consume = g_thread_create(threaded_consume, q, TRUE, NULL);
++ g_thread_join(thread_feed);
++ g_thread_join(thread_consume);
++
++ log_queue_free(q);
++ }
++}
++#endif
++
+ int
+ main()
+ {
+diff --git a/tests/unit/test_template.c b/tests/unit/test_template.c
+index 675b9d6..c499d8d 100644
+--- a/tests/unit/test_template.c
++++ b/tests/unit/test_template.c
+@@ -18,9 +18,13 @@ testcase(LogMessage *msg, gchar *template, gchar *expected)
+ {
+ LogTemplate *templ;
+ GString *res = g_string_sized_new(128);
++ static TimeZoneInfo *tzinfo = NULL;
++
++ if (!tzinfo)
++ tzinfo = time_zone_info_new(NULL);
+
+ templ = log_template_new("dummy", template);
+- log_template_format(templ, msg, LT_ESCAPE, TS_FMT_BSD, NULL, 3, 0, res);
++ log_template_format(templ, msg, LT_ESCAPE, TS_FMT_BSD, tzinfo, 3, 0, res);
+
+ if (strcmp(res->str, expected) != 0)
{
- g_process_cap_restore(saved_caps);
+@@ -39,7 +43,7 @@ int
+ main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED)
+ {
+ LogMessage *msg;
+- char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]: árvíztűrőtükörfúrógép";
++ char *msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép";
+ GlobalConfig dummy;
+
+ if (argc > 1)
+@@ -172,6 +176,14 @@ main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED)
+ testcase(msg, "$PID", "");
+ log_msg_unref(msg);
+
++ msg_str = "<155>2006-02-11T10:34:56+01:00 bzorp syslog-ng[23323]:árvíztűrőtükörfúrógép";
++
++ msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), LP_STORE_LEGACY_MSGHDR, NULL, -1);
++
++ testcase(msg, "$LEGACY_MSGHDR", "syslog-ng[23323]:");
++ testcase(msg, "$MSGHDR", "syslog-ng[23323]:");
++ log_msg_unref(msg);
++
+ msg_str = "<132>1 2006-10-29T01:59:59.156+01:00 mymachine evntslog 3535 ID47 [exampleSDID@0 iut=\"3\" eventSource=\"Application\" eventID=\"1011\"][examplePriority@0 class=\"high\"] BOMAn application event log entry...";
+ msg = log_msg_new(msg_str, strlen(msg_str), g_sockaddr_inet_new("10.10.10.10", 1010), LP_SYSLOG_PROTOCOL, NULL, -1);
+
+diff --git a/tgz2build/rules b/tgz2build/rules
+index 57eb338..7f2c776 100644
+--- a/tgz2build/rules
++++ b/tgz2build/rules
+@@ -3,7 +3,7 @@ STAMPDIR=tgz2build/stamps
+ DOCDIR=$(PREFIX)/doc
+
+
+-CONFIGURE_OPTS := --prefix $(ZBS_PREFIX) --enable-ssl --enable-dynamic-linking --enable-sql --enable-spoof-source --disable-tcp-wrapper --disable-pcre --with-ld-library-path=$(ZBS_PREFIX)/lib
++CONFIGURE_OPTS := --prefix $(ZBS_PREFIX) --enable-ssl --enable-dynamic-linking --enable-sql --enable-spoof-source --disable-tcp-wrapper --disable-pcre --with-ld-library-path=$(ZBS_PREFIX)/lib --with-pidfile-dir=$(ZBS_PREFIX)/var/run
+ INSTALL:=./install-sh
+ RPATH=-Wl,-R/opt/syslog-ng/lib
+