Merge lp:~serge-hallyn/ubuntu/precise/syslog-ng/merge-3.3.1 into lp:ubuntu/precise/syslog-ng

Proposed by Serge Hallyn
Status: Merged
Merge reported by: Dave Walker
Merged at revision: not available
Proposed branch: lp:~serge-hallyn/ubuntu/precise/syslog-ng/merge-3.3.1
Merge into: lp:ubuntu/precise/syslog-ng
Diff against target: 210324 lines (+168503/-14268)
843 files modified
.pc/.version (+1/-0)
.pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.c (+212/-0)
.pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.h (+204/-0)
.pc/LogMatcher-fixed-reference-counting.patch/lib/logmatcher.c (+881/-0)
.pc/LogQueue-added-keep_on_reload-method.patch/lib/driver.c (+205/-0)
.pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue-fifo.c (+463/-0)
.pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue.h (+150/-0)
.pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.c (+1403/-0)
.pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.h (+89/-0)
.pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch/modules/affile/affile.c (+1181/-0)
.pc/afsocket-Fix-compilation-with-libsystemd-daemon.patch/configure.in (+1184/-0)
.pc/afsocket-Fix-compilation-with-libsystemd-daemon.patch/modules/afsocket/afunix.c (+246/-0)
.pc/afsocket-fixed-a-NULL-deref-in-case-of-reload.patch/modules/afsocket/afsocket.c (+1283/-0)
.pc/afsql-allow-initialization-to-continue-even-without-indexes.patch/modules/afsql/afsql.c (+1236/-0)
.pc/afsql-fixed-a-memory-leak-of-the-indexes-array.patch/modules/afsql/afsql.c (+1236/-0)
.pc/afuser-fixed-the-leakage-of-the-username.patch/modules/afuser/afuser.c (+124/-0)
.pc/applied-patches (+17/-0)
.pc/configuration-report-duplicate-configuration-elements.patch/lib/cfg-grammar.y (+894/-0)
.pc/configuration-report-duplicate-configuration-elements.patch/lib/cfg-parser.c (+287/-0)
.pc/configuration-report-duplicate-configuration-elements.patch/lib/cfg.c (+552/-0)
.pc/configuration-report-duplicate-configuration-elements.patch/lib/cfg.h (+168/-0)
.pc/driver-don-t-generate-persist-IDs-for-drivers-that-fail-to-specify-one.patch/lib/driver.h (+208/-0)
.pc/filters-fixed-filter-evaluation.patch/lib/filter.c (+710/-0)
.pc/log_writer_set_options-fixed-a-memory-leak.patch/lib/logwriter.c (+1413/-0)
.pc/logproto-Fix-log_proto_file_writer_flush-s-partial-construction.patch/lib/logproto.c (+2074/-0)
.pc/no_make_in_debian.patch/Makefile.am (+15/-0)
.pc/no_make_in_debian.patch/configure.in (+1185/-0)
.pc/systemd-make-sure-the-acquired-fd-is-in-non-blocking-mode.patch/modules/afsocket/afunix.c (+251/-0)
ChangeLog (+5420/-5)
Makefile.am (+5/-2)
Makefile.in (+86/-16)
NEWS (+801/-486)
README (+0/-8)
VERSION (+1/-1)
aclocal.m4 (+17/-0)
build/Makefile.am (+5/-0)
build/Makefile.in (+460/-0)
build/lex-rules.am (+2/-2)
config.h.in (+30/-17)
configure (+1119/-110)
configure.in (+288/-49)
contrib/Makefile.am (+8/-1)
contrib/Makefile.in (+75/-7)
contrib/fedora-packaging/syslog-ng.conf (+1/-1)
contrib/rhel-packaging/syslog-ng.conf (+1/-1)
contrib/solaris-packaging/syslog-ng.example.xml (+2/-2)
contrib/solaris-packaging/syslog-ng.method (+10/-7)
contrib/syslog-ng.conf.RedHat (+3/-3)
contrib/syslog-ng.conf.doc (+2/-2)
contrib/systemd/syslog-ng.service (+12/-0)
debian/Makefile.am (+0/-18)
debian/README.Debian (+0/-10)
debian/TODO (+20/-0)
debian/autogen.sh (+25/-0)
debian/changelog (+41/-9)
debian/changelog.in (+0/-9)
debian/compat (+1/-1)
debian/conf.d/00load-mongodb.conf (+1/-0)
debian/conf.d/00load-sql.conf (+1/-0)
debian/conf.d/00load-tfjson.conf (+1/-0)
debian/control (+132/-10)
debian/control.d/control.in (+143/-0)
debian/control.d/libsyslog-ng.install (+1/-0)
debian/control.d/libsyslog-ng.lintian-overrides (+2/-0)
debian/copyright (+186/-31)
debian/libsyslog-ng-3.3.1.install (+1/-0)
debian/libsyslog-ng-3.3.1.lintian-overrides (+1/-0)
debian/libsyslog-ng-dev.install (+4/-0)
debian/man/loggen.1.inc (+11/-0)
debian/man/pdbtool.1 (+151/-0)
debian/man/syslog-ng-ctl.1 (+75/-0)
debian/man/syslog-ng.8.inc (+9/-0)
debian/man/update-patterndb.1 (+31/-0)
debian/patches/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch (+92/-0)
debian/patches/LogMatcher-fixed-reference-counting.patch (+47/-0)
debian/patches/LogQueue-added-keep_on_reload-method.patch (+96/-0)
debian/patches/LogWriter-introduce-log_writer_get_queue-method.patch (+49/-0)
debian/patches/affile-release-per-writer-LogQueue-instances-during-runtime.patch (+59/-0)
debian/patches/afsocket-Fix-compilation-with-libsystemd-daemon.patch (+48/-0)
debian/patches/afsocket-fixed-a-NULL-deref-in-case-of-reload.patch (+68/-0)
debian/patches/afsql-allow-initialization-to-continue-even-without-indexes.patch (+30/-0)
debian/patches/afsql-fixed-a-memory-leak-of-the-indexes-array.patch (+28/-0)
debian/patches/afuser-fixed-the-leakage-of-the-username.patch (+45/-0)
debian/patches/configuration-report-duplicate-configuration-elements.patch (+378/-0)
debian/patches/driver-don-t-generate-persist-IDs-for-drivers-that-fail-to-specify-one.patch (+35/-0)
debian/patches/filters-fixed-filter-evaluation.patch (+84/-0)
debian/patches/log_writer_set_options-fixed-a-memory-leak.patch (+38/-0)
debian/patches/logproto-Fix-log_proto_file_writer_flush-s-partial-construction.patch (+49/-0)
debian/patches/no_make_in_debian.patch (+25/-0)
debian/patches/series (+17/-0)
debian/patches/systemd-make-sure-the-acquired-fd-is-in-non-blocking-mode.patch (+32/-0)
debian/rules (+196/-110)
debian/source/options (+2/-0)
debian/syslog-ng-core.dirs (+1/-0)
debian/syslog-ng-core.install (+20/-0)
debian/syslog-ng-core.manpages (+2/-0)
debian/syslog-ng-core.postinst (+15/-0)
debian/syslog-ng-core.postrm (+22/-0)
debian/syslog-ng-core.preinst (+11/-0)
debian/syslog-ng-core.prerm (+11/-0)
debian/syslog-ng-core.syslog-ng.default (+12/-0)
debian/syslog-ng-core.syslog-ng.init (+141/-0)
debian/syslog-ng-core.syslog-ng.logcheck.ignore.paranoid (+2/-0)
debian/syslog-ng-core.syslog-ng.logcheck.ignore.server (+5/-0)
debian/syslog-ng-core.syslog-ng.logcheck.violations.ignore (+1/-0)
debian/syslog-ng-core.syslog-ng.logrotate (+37/-0)
debian/syslog-ng-core.triggers (+2/-0)
debian/syslog-ng-mod-json.dirs (+1/-0)
debian/syslog-ng-mod-json.install (+3/-0)
debian/syslog-ng-mod-json.triggers (+1/-0)
debian/syslog-ng-mod-mongodb.dirs (+1/-0)
debian/syslog-ng-mod-mongodb.install (+3/-0)
debian/syslog-ng-mod-mongodb.triggers (+1/-0)
debian/syslog-ng-mod-sql.dirs (+1/-0)
debian/syslog-ng-mod-sql.install (+3/-0)
debian/syslog-ng-mod-sql.triggers (+1/-0)
debian/syslog-ng.conf (+13/-7)
debian/syslog-ng.conf.example (+0/-149)
debian/syslog-ng.default (+0/-12)
debian/syslog-ng.files (+0/-3)
debian/syslog-ng.init (+0/-128)
debian/syslog-ng.install (+0/-1)
debian/syslog-ng.lintian-overrides (+0/-7)
debian/syslog-ng.logcheck.ignore (+0/-2)
debian/syslog-ng.logcheck.ignore.paranoid (+0/-2)
debian/syslog-ng.logcheck.ignore.server (+0/-5)
debian/syslog-ng.logcheck.violations.ignore (+0/-1)
debian/syslog-ng.logrotate (+0/-136)
debian/syslog-ng.logrotate.example (+0/-123)
debian/syslog-ng.postinst (+0/-69)
debian/syslog-ng.postrm (+0/-25)
debian/syslog-ng.preinst (+0/-14)
debian/syslog-ng.prerm (+0/-17)
debian/tools/help2man.mk (+24/-0)
debian/tools/update-control.sh (+33/-0)
debian/watch (+1/-0)
dist.conf (+1/-1)
doc/Makefile.am (+1/-6)
doc/Makefile.in (+17/-3)
doc/examples/syslog-ng.conf.sample (+0/-89)
doc/examples/syslog-ng.conf.solaris (+0/-15)
doc/examples/syslog-ng.service (+0/-11)
doc/man/loggen.1.in (+0/-186)
doc/man/pdbtool.1.in (+0/-312)
doc/man/syslog-ng-ctl.1.in (+0/-224)
doc/man/syslog-ng.8.in (+0/-192)
doc/man/syslog-ng.conf.5.in (+0/-370)
lib/Makefile.am (+169/-46)
lib/Makefile.in (+482/-115)
lib/afinter.c (+314/-151)
lib/afinter.h (+12/-0)
lib/apphook.c (+18/-9)
lib/atomic.h (+6/-37)
lib/block-ref-grammar.c (+159/-124)
lib/block-ref-grammar.h (+19/-1)
lib/block-ref-grammar.y (+99/-19)
lib/block-ref-grammar.ym (+1/-0)
lib/block-ref-parser.c (+2/-2)
lib/center.c (+139/-92)
lib/center.h (+3/-2)
lib/cfg-grammar.c (+846/-609)
lib/cfg-grammar.h (+35/-2)
lib/cfg-grammar.y (+219/-84)
lib/cfg-lex.c (+1/-1)
lib/cfg-lex.l (+1/-1)
lib/cfg-lexer.c (+14/-7)
lib/cfg-parser.c (+35/-11)
lib/cfg-parser.h (+7/-6)
lib/cfg.c (+67/-156)
lib/cfg.h (+18/-16)
lib/compat.c (+1/-0)
lib/control.c (+219/-125)
lib/control.h (+2/-2)
lib/crypto.c (+126/-0)
lib/crypto.h (+6/-0)
lib/dgroup.c (+7/-2)
lib/dgroup.h (+2/-2)
lib/dnscache.c (+40/-12)
lib/dnscache.h (+2/-2)
lib/driver.c (+171/-19)
lib/driver.h (+168/-20)
lib/filter-expr-grammar.c (+332/-290)
lib/filter-expr-grammar.h (+50/-32)
lib/filter-expr-grammar.y (+107/-24)
lib/filter-expr-grammar.ym (+9/-5)
lib/filter-expr-parser.c (+1/-1)
lib/filter.c (+149/-72)
lib/filter.h (+25/-9)
lib/globals.c (+2/-2)
lib/gprocess.c (+51/-4)
lib/gprocess.h (+6/-0)
lib/gsockaddr.c (+33/-10)
lib/gsocket.c (+0/-108)
lib/gsocket.h (+0/-4)
lib/ivykis/AUTHORS (+1/-0)
lib/ivykis/COPYING (+502/-0)
lib/ivykis/DEDICATION (+1/-0)
lib/ivykis/Makefile.am (+6/-0)
lib/ivykis/Makefile.in (+722/-0)
lib/ivykis/aclocal.m4 (+956/-0)
lib/ivykis/config.h.in (+170/-0)
lib/ivykis/configure (+14113/-0)
lib/ivykis/configure.ac (+207/-0)
lib/ivykis/configure.gnu (+9/-0)
lib/ivykis/contrib/00README.txt (+28/-0)
lib/ivykis/contrib/Makefile.am (+3/-0)
lib/ivykis/contrib/Makefile.in (+554/-0)
lib/ivykis/contrib/iv_inotify/Makefile.am (+11/-0)
lib/ivykis/contrib/iv_inotify/Makefile.in (+473/-0)
lib/ivykis/contrib/iv_inotify/example.c (+154/-0)
lib/ivykis/contrib/iv_inotify/iv_inotify.3 (+133/-0)
lib/ivykis/contrib/iv_inotify/iv_inotify.c (+313/-0)
lib/ivykis/contrib/iv_inotify/iv_inotify.h (+66/-0)
lib/ivykis/contrib/iv_openssl/Makefile.am (+11/-0)
lib/ivykis/contrib/iv_openssl/Makefile.in (+473/-0)
lib/ivykis/contrib/iv_openssl/echo.c (+183/-0)
lib/ivykis/contrib/iv_openssl/iv_openssl.c (+269/-0)
lib/ivykis/contrib/iv_openssl/iv_openssl.h (+69/-0)
lib/ivykis/contrib/iv_openssl/mkkeycert (+4/-0)
lib/ivykis/contrib/kojines/00README.txt (+34/-0)
lib/ivykis/contrib/kojines/Makefile.am (+11/-0)
lib/ivykis/contrib/kojines/Makefile.in (+473/-0)
lib/ivykis/contrib/kojines/kojines.c (+544/-0)
lib/ivykis/contrib/kojines/kojines.h (+31/-0)
lib/ivykis/contrib/kojines/main.c (+39/-0)
lib/ivykis/contrib/splice/Makefile.am (+10/-0)
lib/ivykis/contrib/splice/Makefile.in (+480/-0)
lib/ivykis/contrib/splice/discard.c (+153/-0)
lib/ivykis/contrib/splice/echo.c (+225/-0)
lib/ivykis/ivykis.spec (+80/-0)
lib/ivykis/ivykis.spec.in (+80/-0)
lib/ivykis/lib/Makefile.am (+38/-0)
lib/ivykis/lib/Makefile.in (+730/-0)
lib/ivykis/lib/include/iv.h (+130/-0)
lib/ivykis/lib/include/iv_avl.h (+110/-0)
lib/ivykis/lib/include/iv_compat.h (+80/-0)
lib/ivykis/lib/include/iv_config.h (+10/-0)
lib/ivykis/lib/include/iv_list.h (+146/-0)
lib/ivykis/lib/iv_avl.c (+436/-0)
lib/ivykis/lib/iv_main.c (+463/-0)
lib/ivykis/lib/iv_method_dev_poll.c (+252/-0)
lib/ivykis/lib/iv_method_epoll.c (+182/-0)
lib/ivykis/lib/iv_method_kqueue.c (+233/-0)
lib/ivykis/lib/iv_method_poll.c (+169/-0)
lib/ivykis/lib/iv_method_select.c (+227/-0)
lib/ivykis/lib/iv_private.h (+143/-0)
lib/ivykis/lib/iv_task.c (+104/-0)
lib/ivykis/lib/iv_thr.h (+156/-0)
lib/ivykis/lib/iv_timer.c (+354/-0)
lib/ivykis/lib/man3/Makefile.am (+24/-0)
lib/ivykis/lib/man3/Makefile.in (+452/-0)
lib/ivykis/lib/man3/iv_deinit.3 (+1/-0)
lib/ivykis/lib/man3/iv_examples.3 (+363/-0)
lib/ivykis/lib/man3/iv_fd.3 (+146/-0)
lib/ivykis/lib/man3/iv_fd_register.3 (+1/-0)
lib/ivykis/lib/man3/iv_fd_set_handler_err.3 (+1/-0)
lib/ivykis/lib/man3/iv_fd_set_handler_in.3 (+1/-0)
lib/ivykis/lib/man3/iv_fd_set_handler_out.3 (+1/-0)
lib/ivykis/lib/man3/iv_fd_unregister.3 (+1/-0)
lib/ivykis/lib/man3/iv_init.3 (+47/-0)
lib/ivykis/lib/man3/iv_inited.3 (+1/-0)
lib/ivykis/lib/man3/iv_invalidate_now.3 (+1/-0)
lib/ivykis/lib/man3/iv_main.3 (+30/-0)
lib/ivykis/lib/man3/iv_quit.3 (+26/-0)
lib/ivykis/lib/man3/iv_task.3 (+72/-0)
lib/ivykis/lib/man3/iv_task_register.3 (+1/-0)
lib/ivykis/lib/man3/iv_task_unregister.3 (+1/-0)
lib/ivykis/lib/man3/iv_time.3 (+39/-0)
lib/ivykis/lib/man3/iv_timer.3 (+70/-0)
lib/ivykis/lib/man3/iv_timer_register.3 (+1/-0)
lib/ivykis/lib/man3/iv_timer_unregister.3 (+1/-0)
lib/ivykis/lib/man3/iv_validate_now.3 (+1/-0)
lib/ivykis/lib/man3/ivykis.3 (+75/-0)
lib/ivykis/lib/test/Makefile.am (+29/-0)
lib/ivykis/lib/test/Makefile.in (+567/-0)
lib/ivykis/lib/test/avl.c (+203/-0)
lib/ivykis/lib/test/client.c (+101/-0)
lib/ivykis/lib/test/connectfail.c (+74/-0)
lib/ivykis/lib/test/connectreset.c (+178/-0)
lib/ivykis/lib/test/null.c (+45/-0)
lib/ivykis/lib/test/server.c (+159/-0)
lib/ivykis/lib/test/timer.c (+56/-0)
lib/ivykis/lib/test/timer_rat.c (+69/-0)
lib/ivykis/m4/libtool.m4 (+7377/-0)
lib/ivykis/m4/ltoptions.m4 (+368/-0)
lib/ivykis/m4/ltsugar.m4 (+123/-0)
lib/ivykis/m4/ltversion.m4 (+23/-0)
lib/ivykis/m4/lt~obsolete.m4 (+92/-0)
lib/ivykis/misc/Makefile.am (+3/-0)
lib/ivykis/misc/Makefile.in (+405/-0)
lib/ivykis/misc/ivykis-modules.pc.in (+11/-0)
lib/ivykis/misc/ivykis.pc.in (+11/-0)
lib/ivykis/modules/Makefile.am (+30/-0)
lib/ivykis/modules/Makefile.in (+722/-0)
lib/ivykis/modules/include/iv_event.h (+52/-0)
lib/ivykis/modules/include/iv_event_raw.h (+51/-0)
lib/ivykis/modules/include/iv_popen.h (+48/-0)
lib/ivykis/modules/include/iv_signal.h (+56/-0)
lib/ivykis/modules/include/iv_thread.h (+39/-0)
lib/ivykis/modules/include/iv_wait.h (+62/-0)
lib/ivykis/modules/include/iv_work.h (+70/-0)
lib/ivykis/modules/iv_event.c (+124/-0)
lib/ivykis/modules/iv_event_raw.c (+156/-0)
lib/ivykis/modules/iv_popen.c (+197/-0)
lib/ivykis/modules/iv_signal.c (+158/-0)
lib/ivykis/modules/iv_thread.c (+202/-0)
lib/ivykis/modules/iv_wait.c (+295/-0)
lib/ivykis/modules/iv_work.c (+342/-0)
lib/ivykis/modules/man3/IV_EVENT_INIT.3 (+1/-0)
lib/ivykis/modules/man3/IV_EVENT_RAW_INIT.3 (+1/-0)
lib/ivykis/modules/man3/IV_POPEN_REQUEST_INIT.3 (+1/-0)
lib/ivykis/modules/man3/IV_SIGNAL_INIT.3 (+1/-0)
lib/ivykis/modules/man3/IV_WAIT_INTEREST_INIT.3 (+1/-0)
lib/ivykis/modules/man3/IV_WORK_ITEM_INIT.3 (+1/-0)
lib/ivykis/modules/man3/IV_WORK_POOL_INIT.3 (+1/-0)
lib/ivykis/modules/man3/Makefile.am (+34/-0)
lib/ivykis/modules/man3/Makefile.in (+462/-0)
lib/ivykis/modules/man3/iv_event.3 (+92/-0)
lib/ivykis/modules/man3/iv_event_post.3 (+1/-0)
lib/ivykis/modules/man3/iv_event_raw.3 (+111/-0)
lib/ivykis/modules/man3/iv_event_raw_post.3 (+1/-0)
lib/ivykis/modules/man3/iv_event_raw_register.3 (+1/-0)
lib/ivykis/modules/man3/iv_event_raw_unregister.3 (+1/-0)
lib/ivykis/modules/man3/iv_event_register.3 (+1/-0)
lib/ivykis/modules/man3/iv_event_unregister.3 (+1/-0)
lib/ivykis/modules/man3/iv_popen.3 (+90/-0)
lib/ivykis/modules/man3/iv_popen_request_close.3 (+1/-0)
lib/ivykis/modules/man3/iv_popen_request_submit.3 (+1/-0)
lib/ivykis/modules/man3/iv_signal.3 (+110/-0)
lib/ivykis/modules/man3/iv_signal_register.3 (+1/-0)
lib/ivykis/modules/man3/iv_signal_unregister.3 (+1/-0)
lib/ivykis/modules/man3/iv_thread.3 (+63/-0)
lib/ivykis/modules/man3/iv_thread_create.3 (+1/-0)
lib/ivykis/modules/man3/iv_thread_set_debug_state.3 (+1/-0)
lib/ivykis/modules/man3/iv_wait.3 (+129/-0)
lib/ivykis/modules/man3/iv_wait_interest_register.3 (+1/-0)
lib/ivykis/modules/man3/iv_wait_interest_register_spawn.3 (+1/-0)
lib/ivykis/modules/man3/iv_wait_interest_unregister.3 (+1/-0)
lib/ivykis/modules/man3/iv_work.3 (+147/-0)
lib/ivykis/modules/man3/iv_work_pool_create.3 (+1/-0)
lib/ivykis/modules/man3/iv_work_pool_put.3 (+1/-0)
lib/ivykis/modules/man3/iv_work_pool_submit_work.3 (+1/-0)
lib/ivykis/modules/test/Makefile.am (+26/-0)
lib/ivykis/modules/test/Makefile.in (+557/-0)
lib/ivykis/modules/test/iv_event_raw_test.c (+77/-0)
lib/ivykis/modules/test/iv_event_test.c (+108/-0)
lib/ivykis/modules/test/iv_popen_test.c (+122/-0)
lib/ivykis/modules/test/iv_signal_child_test.c (+64/-0)
lib/ivykis/modules/test/iv_signal_test.c (+63/-0)
lib/ivykis/modules/test/iv_thread_test.c (+58/-0)
lib/ivykis/modules/test/iv_wait_test.c (+133/-0)
lib/ivykis/modules/test/iv_work_test.c (+98/-0)
lib/logmatcher.c (+30/-10)
lib/logmatcher.h (+3/-7)
lib/logmpx.c (+19/-22)
lib/logmpx.h (+0/-6)
lib/logmsg.c (+762/-180)
lib/logmsg.h (+73/-28)
lib/logparser.c (+43/-80)
lib/logparser.h (+11/-37)
lib/logpipe.c (+7/-15)
lib/logpipe.h (+192/-21)
lib/logprocess.c (+21/-67)
lib/logprocess.h (+36/-58)
lib/logproto.c (+336/-54)
lib/logproto.h (+17/-4)
lib/logqueue-fifo.c (+471/-0)
lib/logqueue-fifo.h (+32/-0)
lib/logqueue.c (+198/-191)
lib/logqueue.h (+126/-9)
lib/logreader.c (+415/-227)
lib/logreader.h (+2/-17)
lib/logrewrite.c (+80/-94)
lib/logrewrite.h (+2/-6)
lib/logsource.c (+203/-65)
lib/logsource.h (+22/-10)
lib/logstamp.c (+58/-36)
lib/logstamp.h (+3/-2)
lib/logtransport.c (+30/-1)
lib/logtransport.h (+14/-0)
lib/logwriter.c (+826/-404)
lib/logwriter.h (+14/-33)
lib/mainloop.c (+754/-0)
lib/mainloop.h (+95/-0)
lib/merge-grammar.pl (+46/-0)
lib/messages.c (+24/-29)
lib/messages.h (+3/-26)
lib/misc.c (+115/-30)
lib/misc.h (+8/-3)
lib/msg-format.h (+2/-0)
lib/nvtable.c (+72/-31)
lib/nvtable.h (+23/-2)
lib/parser-expr-grammar.c (+158/-121)
lib/parser-expr-grammar.h (+19/-1)
lib/parser-expr-grammar.y (+100/-20)
lib/parser-expr-grammar.ym (+2/-1)
lib/parser-expr-parser.c (+1/-1)
lib/persist-state.c (+42/-5)
lib/plugin.c (+175/-50)
lib/plugin.h (+19/-1)
lib/pragma-grammar.c (+190/-154)
lib/pragma-grammar.h (+24/-6)
lib/pragma-grammar.y (+99/-19)
lib/pragma-grammar.ym (+1/-0)
lib/pragma-parser.c (+2/-2)
lib/rewrite-expr-grammar.c (+237/-168)
lib/rewrite-expr-grammar.h (+20/-2)
lib/rewrite-expr-grammar.y (+132/-21)
lib/rewrite-expr-grammar.ym (+34/-2)
lib/rewrite-expr-parser.c (+1/-1)
lib/serialize.c (+6/-4)
lib/sgroup.c (+8/-4)
lib/sgroup.h (+1/-1)
lib/stats.c (+159/-28)
lib/stats.h (+85/-27)
lib/str-format.c (+373/-0)
lib/str-format.h (+21/-0)
lib/syslog-names.h (+9/-0)
lib/syslog-ng.h (+2/-3)
lib/tags.c (+81/-11)
lib/tags.h (+14/-1)
lib/templates.c (+94/-75)
lib/templates.h (+17/-12)
lib/timeutils.c (+201/-85)
lib/timeutils.h (+10/-1)
lib/tls-support.h (+88/-0)
lib/tlscontext.c (+557/-0)
lib/tlscontext.h (+99/-0)
lib/tlstransport.c (+177/-0)
lib/tlstransport.h (+33/-0)
lib/value-pairs.c (+483/-0)
lib/value-pairs.h (+49/-0)
modules/Makefile.am (+1/-1)
modules/Makefile.in (+18/-1)
modules/affile/Makefile.in (+19/-2)
modules/affile/affile-grammar.c (+730/-564)
modules/affile/affile-grammar.h (+26/-8)
modules/affile/affile-grammar.y (+139/-51)
modules/affile/affile-grammar.ym (+41/-32)
modules/affile/affile-parser.c (+2/-2)
modules/affile/affile-plugin.c (+10/-0)
modules/affile/affile.c (+376/-156)
modules/affile/affile.h (+3/-3)
modules/afmongodb/Makefile.am (+35/-0)
modules/afmongodb/Makefile.in (+803/-0)
modules/afmongodb/TODO (+20/-0)
modules/afmongodb/afmongodb-grammar.c (+3222/-0)
modules/afmongodb/afmongodb-grammar.h (+350/-0)
modules/afmongodb/afmongodb-grammar.y (+531/-0)
modules/afmongodb/afmongodb-grammar.ym (+81/-0)
modules/afmongodb/afmongodb-parser.c (+54/-0)
modules/afmongodb/afmongodb-parser.h (+35/-0)
modules/afmongodb/afmongodb.c (+593/-0)
modules/afmongodb/afmongodb.h (+40/-0)
modules/afmongodb/libmongo-client/Doxyfile.in (+152/-0)
modules/afmongodb/libmongo-client/Makefile.am (+12/-0)
modules/afmongodb/libmongo-client/Makefile.in (+743/-0)
modules/afmongodb/libmongo-client/NEWS (+169/-0)
modules/afmongodb/libmongo-client/README.rst (+66/-0)
modules/afmongodb/libmongo-client/aclocal.m4 (+1036/-0)
modules/afmongodb/libmongo-client/config.guess (+1502/-0)
modules/afmongodb/libmongo-client/config.h.in (+128/-0)
modules/afmongodb/libmongo-client/config.sub (+1714/-0)
modules/afmongodb/libmongo-client/configure (+14606/-0)
modules/afmongodb/libmongo-client/configure.ac (+147/-0)
modules/afmongodb/libmongo-client/configure.gnu (+7/-0)
modules/afmongodb/libmongo-client/depcomp (+630/-0)
modules/afmongodb/libmongo-client/docs/Makefile.am (+2/-0)
modules/afmongodb/libmongo-client/docs/Makefile.in (+568/-0)
modules/afmongodb/libmongo-client/docs/tutorial/Makefile.am (+13/-0)
modules/afmongodb/libmongo-client/docs/tutorial/Makefile.in (+379/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/GNUmakefile (+34/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/tut_bson_build.c (+81/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/tut_bson_build.json (+16/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/tut_bson_traverse.c (+123/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/tut_hl_client.c (+107/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/tut_json2bson.c (+132/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/tut_mongo_sync.c (+273/-0)
modules/afmongodb/libmongo-client/docs/tutorial/examples/tut_mongo_sync_cmd_create.c (+82/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_bson.h (+10/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_bson_build.h (+62/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_bson_traverse.h (+135/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_hl_client.h (+86/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_json2bson.h (+97/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_mongo_sync.h (+14/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_mongo_sync_cmd_create.h (+53/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_mongo_sync_connect.h (+49/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_mongo_sync_insert.h (+46/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_mongo_sync_query.h (+67/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tut_mongo_sync_query_complex.h (+43/-0)
modules/afmongodb/libmongo-client/docs/tutorial/tutorial.h (+32/-0)
modules/afmongodb/libmongo-client/examples/Makefile.am (+8/-0)
modules/afmongodb/libmongo-client/examples/Makefile.in (+519/-0)
modules/afmongodb/libmongo-client/examples/bson-inspect.c (+341/-0)
modules/afmongodb/libmongo-client/examples/gridfs.c (+409/-0)
modules/afmongodb/libmongo-client/examples/mongo-dump.c (+212/-0)
modules/afmongodb/libmongo-client/install-sh (+520/-0)
modules/afmongodb/libmongo-client/ltmain.sh (+8413/-0)
modules/afmongodb/libmongo-client/m4/libtool.m4 (+7377/-0)
modules/afmongodb/libmongo-client/m4/ltoptions.m4 (+368/-0)
modules/afmongodb/libmongo-client/m4/ltsugar.m4 (+123/-0)
modules/afmongodb/libmongo-client/m4/ltversion.m4 (+23/-0)
modules/afmongodb/libmongo-client/m4/lt~obsolete.m4 (+92/-0)
modules/afmongodb/libmongo-client/m4/pkg.m4 (+157/-0)
modules/afmongodb/libmongo-client/missing (+376/-0)
modules/afmongodb/libmongo-client/src/Makefile.am (+45/-0)
modules/afmongodb/libmongo-client/src/Makefile.in (+748/-0)
modules/afmongodb/libmongo-client/src/bson.c (+1251/-0)
modules/afmongodb/libmongo-client/src/bson.h (+856/-0)
modules/afmongodb/libmongo-client/src/compat.c (+108/-0)
modules/afmongodb/libmongo-client/src/compat.h (+44/-0)
modules/afmongodb/libmongo-client/src/libmongo-client.pc.in (+12/-0)
modules/afmongodb/libmongo-client/src/libmongo-macros.h (+51/-0)
modules/afmongodb/libmongo-client/src/libmongo-private.h (+251/-0)
modules/afmongodb/libmongo-client/src/mongo-client.c (+285/-0)
modules/afmongodb/libmongo-client/src/mongo-client.h (+107/-0)
modules/afmongodb/libmongo-client/src/mongo-sync-cursor.c (+118/-0)
modules/afmongodb/libmongo-client/src/mongo-sync-cursor.h (+103/-0)
modules/afmongodb/libmongo-client/src/mongo-sync-pool.c (+269/-0)
modules/afmongodb/libmongo-client/src/mongo-sync-pool.h (+133/-0)
modules/afmongodb/libmongo-client/src/mongo-sync.c (+1829/-0)
modules/afmongodb/libmongo-client/src/mongo-sync.h (+548/-0)
modules/afmongodb/libmongo-client/src/mongo-utils.c (+191/-0)
modules/afmongodb/libmongo-client/src/mongo-utils.h (+121/-0)
modules/afmongodb/libmongo-client/src/mongo-wire.c (+645/-0)
modules/afmongodb/libmongo-client/src/mongo-wire.h (+433/-0)
modules/afmongodb/libmongo-client/src/mongo.h (+49/-0)
modules/afmongodb/libmongo-client/src/sync-gridfs-chunk.c (+314/-0)
modules/afmongodb/libmongo-client/src/sync-gridfs-chunk.h (+134/-0)
modules/afmongodb/libmongo-client/src/sync-gridfs-stream.c (+495/-0)
modules/afmongodb/libmongo-client/src/sync-gridfs-stream.h (+141/-0)
modules/afmongodb/libmongo-client/src/sync-gridfs.c (+345/-0)
modules/afmongodb/libmongo-client/src/sync-gridfs.h (+193/-0)
modules/afmongodb/libmongo-client/tests/Makefile.am (+227/-0)
modules/afmongodb/libmongo-client/tests/Makefile.in (+5248/-0)
modules/afmongodb/libmongo-client/tests/README (+28/-0)
modules/afmongodb/libmongo-client/tests/coverage.sh (+43/-0)
modules/afmongodb/libmongo-client/tests/func/bson/f_weird_types.c (+71/-0)
modules/afmongodb/libmongo-client/tests/func/bson/huge_doc.c (+51/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/client/f_client_big_packet.c (+57/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync-cursor/f_sync_cursor_iterate.c (+88/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync-cursor/f_sync_cursor_tailable.c (+115/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync-gridfs-chunk/f_sync_gridfs_chunk.c (+414/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync-gridfs-stream/f_sync_gridfs_stream.c (+392/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync-pool/f_sync_pool.c (+169/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync/f_sync_auto_reconnect.c (+61/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync/f_sync_conn_seed_add.c (+58/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync/f_sync_max_insert_size.c (+69/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync/f_sync_oidtest.c (+44/-0)
modules/afmongodb/libmongo-client/tests/func/mongo/sync/f_sync_safe_mode.c (+79/-0)
modules/afmongodb/libmongo-client/tests/libtap/Makefile.am (+4/-0)
modules/afmongodb/libmongo-client/tests/libtap/Makefile.in (+516/-0)
modules/afmongodb/libmongo-client/tests/libtap/tap.c (+294/-0)
modules/afmongodb/libmongo-client/tests/libtap/tap.h (+85/-0)
modules/afmongodb/libmongo-client/tests/libtap/test.c (+170/-0)
modules/afmongodb/libmongo-client/tests/libtap/test.h (+81/-0)
modules/afmongodb/libmongo-client/tests/perf/bson/p_bson_find.c (+43/-0)
modules/afmongodb/libmongo-client/tests/test_cleanup.c (+31/-0)
modules/afmongodb/libmongo-client/tests/tools/coverage-report-entry.pl (+70/-0)
modules/afmongodb/libmongo-client/tests/tools/coverage-report.pl (+125/-0)
modules/afmongodb/libmongo-client/tests/tools/coverage-report.xsl (+235/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_array.c (+65/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_binary.c (+56/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_boolean.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_document.c (+67/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_double.c (+41/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_int32.c (+40/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_int64.c (+41/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_js_code.c (+66/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_js_code_w_scope.c (+79/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_null.c (+40/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_oid.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_regexp.c (+45/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_string.c (+61/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_symbol.c (+61/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_timestamp.c (+41/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_append_utc_datetime.c (+41/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_build.c (+70/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_build_full.c (+71/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_find.c (+36/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_find_next.c (+33/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_array.c (+44/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_binary.c (+60/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_boolean.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_document.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_double.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_int32.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_int64.c (+45/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_javascript.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_javascript_w_scope.c (+57/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_oid.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_regex.c (+52/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_string.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_symbol.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_timestamp.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_get_utc_datetime.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_key.c (+30/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_new.c (+28/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_next.c (+42/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_type.c (+30/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_cursor_type_as_string.c (+31/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_empty.c (+22/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_find.c (+34/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_new.c (+28/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_new_from_data.c (+46/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_reset.c (+27/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_type_as_string.c (+40/-0)
modules/afmongodb/libmongo-client/tests/unit/bson/bson_validate_key.c (+36/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/client/connect.c (+32/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/client/connection_get_requestid.c (+44/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/client/connection_set_timeout.c (+33/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/client/disconnect.c (+32/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/client/packet_recv.c (+56/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/client/packet_send.c (+75/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-cursor/sync_cursor_free.c (+34/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-cursor/sync_cursor_get_data.c (+51/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-cursor/sync_cursor_new.c (+40/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-cursor/sync_cursor_next.c (+40/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_get_chunk.c (+15/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_cursor_new.c (+19/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_free.c (+16/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_file_new_from_buffer.c (+71/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-chunk/sync_gridfs_chunked_find.c (+38/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_close.c (+41/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_find.c (+36/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_new.c (+43/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_read.c (+44/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_seek.c (+65/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs-stream/sync_gridfs_stream_write.c (+50/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs/sync_gridfs_file_get_metadata.c (+23/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs/sync_gridfs_free.c (+35/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs/sync_gridfs_get_set_chunk_size.c (+33/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs/sync_gridfs_list.c (+34/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs/sync_gridfs_new.c (+54/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-gridfs/sync_gridfs_remove.c (+34/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-pool/sync_pool_free.c (+11/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-pool/sync_pool_new.c (+19/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-pool/sync_pool_pick.c (+11/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync-pool/sync_pool_return.c (+22/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_authenticate.c (+112/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_count.c (+119/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_create.c (+78/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_custom.c (+100/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_delete.c (+135/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_drop.c (+93/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_exists.c (+85/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_get_last_error.c (+35/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_get_more.c (+135/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_index_create.c (+62/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_index_drop.c (+51/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_index_drop_all.c (+49/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_insert.c (+78/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_insert_n.c (+100/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_is_master.c (+65/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_kill_cursors.c (+123/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_ping.c (+81/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_query.c (+125/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_reset_error.c (+31/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_update.c (+97/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_user_add.c (+95/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_cmd_user_remove.c (+92/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_conn_seed_add.c (+24/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_connect.c (+22/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_disconnect.c (+22/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_get_set_auto_reconnect.c (+39/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_get_set_max_insert_size.c (+44/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_get_set_safe_mode.c (+38/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_get_set_slaveok.c (+38/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/sync/sync_reconnect.c (+143/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/utils/oid_as_string.c (+26/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/utils/oid_init.c (+19/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/utils/oid_new.c (+49/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/utils/oid_new_with_time.c (+46/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/utils/parse_addr.c (+232/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_custom.c (+67/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_delete.c (+73/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_get_more.c (+50/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_insert.c (+83/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_insert_n.c (+95/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_kill_cursors.c (+58/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_query.c (+117/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/cmd_update.c (+97/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/packet_get_set_data.c (+65/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/packet_get_set_header.c (+58/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/packet_get_set_header_raw.c (+56/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/packet_new.c (+20/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/reply_packet_get_data.c (+52/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/reply_packet_get_header.c (+54/-0)
modules/afmongodb/libmongo-client/tests/unit/mongo/wire/reply_packet_get_nth_document.c (+68/-0)
modules/afprog/Makefile.in (+19/-2)
modules/afprog/afprog-grammar.c (+515/-426)
modules/afprog/afprog-grammar.h (+20/-2)
modules/afprog/afprog-grammar.y (+117/-29)
modules/afprog/afprog-grammar.ym (+19/-10)
modules/afprog/afprog-parser.c (+2/-2)
modules/afprog/afprog-plugin.c (+10/-0)
modules/afprog/afprog.c (+101/-66)
modules/afprog/afprog.h (+2/-2)
modules/afsocket/Makefile.am (+8/-6)
modules/afsocket/Makefile.in (+33/-53)
modules/afsocket/afinet.c (+314/-110)
modules/afsocket/afinet.h (+15/-28)
modules/afsocket/afsocket-grammar.c (+1059/-976)
modules/afsocket/afsocket-grammar.h (+21/-1)
modules/afsocket/afsocket-grammar.y (+182/-99)
modules/afsocket/afsocket-grammar.ym (+84/-80)
modules/afsocket/afsocket-parser.c (+3/-2)
modules/afsocket/afsocket-plugin.c (+10/-1)
modules/afsocket/afsocket.c (+306/-201)
modules/afsocket/afsocket.h (+63/-10)
modules/afsocket/afunix.c (+73/-25)
modules/afsocket/afunix.h (+1/-0)
modules/afsocket/tlscontext.c (+0/-552)
modules/afsocket/tlscontext.h (+0/-101)
modules/afsocket/tlstransport.c (+0/-177)
modules/afsocket/tlstransport.h (+0/-33)
modules/afsql/Makefile.am (+1/-1)
modules/afsql/Makefile.in (+21/-4)
modules/afsql/afsql-grammar.c (+401/-274)
modules/afsql/afsql-grammar.h (+23/-1)
modules/afsql/afsql-grammar.y (+145/-41)
modules/afsql/afsql-grammar.ym (+47/-22)
modules/afsql/afsql-parser.c (+5/-2)
modules/afsql/afsql-plugin.c (+10/-0)
modules/afsql/afsql.c (+216/-170)
modules/afsql/afsql.h (+9/-5)
modules/afstreams/Makefile.in (+19/-2)
modules/afstreams/afstreams-grammar.c (+177/-138)
modules/afstreams/afstreams-grammar.h (+18/-0)
modules/afstreams/afstreams-grammar.y (+105/-23)
modules/afstreams/afstreams-grammar.ym (+7/-4)
modules/afstreams/afstreams-parser.c (+2/-2)
modules/afstreams/afstreams-plugin.c (+10/-0)
modules/afstreams/afstreams.c (+19/-12)
modules/afuser/Makefile.in (+19/-2)
modules/afuser/afuser-grammar.c (+160/-122)
modules/afuser/afuser-grammar.h (+20/-2)
modules/afuser/afuser-grammar.y (+103/-21)
modules/afuser/afuser-grammar.ym (+5/-2)
modules/afuser/afuser-parser.c (+2/-2)
modules/afuser/afuser-plugin.c (+10/-0)
modules/afuser/afuser.c (+16/-20)
modules/basicfuncs/Makefile.in (+17/-0)
modules/basicfuncs/basic-funcs.c (+57/-13)
modules/confgen/Makefile.in (+19/-2)
modules/confgen/confgen-plugin.c (+11/-0)
modules/convertfuncs/Makefile.in (+17/-0)
modules/convertfuncs/convert-funcs.c (+10/-0)
modules/csvparser/Makefile.in (+19/-2)
modules/csvparser/csvparser-grammar.c (+209/-171)
modules/csvparser/csvparser-grammar.h (+20/-2)
modules/csvparser/csvparser-grammar.y (+114/-31)
modules/csvparser/csvparser-grammar.ym (+16/-12)
modules/csvparser/csvparser-parser.c (+2/-2)
modules/csvparser/csvparser-plugin.c (+10/-0)
modules/csvparser/csvparser.c (+24/-2)
modules/dbparser/Makefile.in (+19/-2)
modules/dbparser/dbparser-grammar.c (+228/-141)
modules/dbparser/dbparser-grammar.h (+22/-2)
modules/dbparser/dbparser-grammar.y (+113/-22)
modules/dbparser/dbparser-grammar.ym (+15/-3)
modules/dbparser/dbparser-parser.c (+3/-2)
modules/dbparser/dbparser-plugin.c (+10/-0)
modules/dbparser/dbparser.c (+119/-45)
modules/dbparser/dbparser.h (+1/-0)
modules/dbparser/patterndb-int.h (+2/-1)
modules/dbparser/patterndb.c (+58/-34)
modules/dbparser/patternize.c (+82/-36)
modules/dbparser/patternize.h (+7/-5)
modules/dbparser/pdbtool.c (+153/-13)
modules/dbparser/radix.c (+41/-20)
modules/dbparser/tests/Makefile.in (+17/-0)
modules/dbparser/tests/test_patterndb.c (+21/-4)
modules/dbparser/tests/test_patternize.c (+7/-5)
modules/dbparser/tests/test_radix.c (+17/-0)
modules/dummy/Makefile.in (+19/-2)
modules/dummy/dummy-grammar.c (+243/-149)
modules/dummy/dummy-grammar.h (+22/-4)
modules/dummy/dummy-grammar.y (+106/-22)
modules/dummy/dummy-grammar.ym (+8/-3)
modules/dummy/dummy-parser.c (+3/-3)
modules/dummy/dummy-parser.h (+1/-1)
modules/dummy/dummy.c (+15/-19)
modules/dummy/dummy.h (+2/-2)
modules/pacctformat/Makefile.in (+19/-2)
modules/pacctformat/pacct-format-plugin.c (+10/-0)
modules/syslogformat/Makefile.in (+19/-2)
modules/syslogformat/syslog-format-plugin.c (+10/-0)
modules/syslogformat/syslog-format.c (+67/-117)
modules/tfjson/Makefile.am (+11/-0)
modules/tfjson/Makefile.in (+584/-0)
modules/tfjson/tfjson.c (+167/-0)
scl/Makefile.am (+6/-0)
scl/Makefile.in (+25/-2)
scl/modules.conf (+10/-8)
scl/pacct/plugin.conf (+2/-4)
scl/scl.conf (+2/-4)
scl/syslog-ng.conf (+1/-1)
scl/syslogconf/plugin.conf (+2/-4)
scl/system/generate-system-source.sh (+38/-4)
scl/system/plugin.conf (+2/-4)
scripts/Makefile.in (+17/-0)
syslog-ng.pc.in (+14/-0)
syslog-ng.spec (+12/-12)
syslog-ng/Makefile.in (+17/-0)
syslog-ng/main.c (+66/-257)
syslog-ng/syslog-ng-ctl.c (+2/-0)
tests/Makefile.in (+17/-0)
tests/functional/Makefile.am (+2/-0)
tests/functional/Makefile.in (+19/-0)
tests/functional/func_test.py (+5/-0)
tests/functional/globals.py (+6/-0)
tests/functional/test_file_source.py (+2/-2)
tests/functional/test_filters.py (+2/-2)
tests/functional/test_input_drivers.py (+2/-2)
tests/functional/test_performance.py (+3/-3)
tests/functional/test_sql.py (+33/-10)
tests/loggen/Makefile.am (+1/-1)
tests/loggen/Makefile.in (+18/-1)
tests/loggen/loggen.c (+489/-253)
tests/unit/Makefile.am (+26/-5)
tests/unit/Makefile.in (+44/-5)
tests/unit/test_clone_logmsg.c (+12/-8)
tests/unit/test_csvparser.c (+6/-2)
tests/unit/test_dnscache.c (+157/-38)
tests/unit/test_filters.c (+38/-25)
tests/unit/test_logqueue.c (+143/-46)
tests/unit/test_logwriter.c (+54/-46)
tests/unit/test_matcher.c (+14/-5)
tests/unit/test_msgparse.c (+179/-5)
tests/unit/test_msgsdata.c (+1/-1)
tests/unit/test_persist_state.c (+3/-0)
tests/unit/test_tags.c (+24/-10)
tests/unit/test_template.c (+96/-7)
tests/unit/test_template_speed.c (+25/-6)
tests/unit/test_thread_wakeup.c (+173/-0)
tests/unit/test_value_pairs.c (+126/-0)
tests/unit/test_zone.c (+43/-2)
tgz2build/Makefile.am (+1/-1)
tgz2build/Makefile.in (+18/-1)
tgz2build/rules (+0/-1)
tgz2build/syslog-ng-dev.files (+5/-0)
tgz2build/tgz2deps (+2/-0)
To merge this branch: bzr merge lp:~serge-hallyn/ubuntu/precise/syslog-ng/merge-3.3.1
Reviewer Review Type Date Requested Status
Dave Walker Pending
Review via email: mp+82333@code.launchpad.net

Description of the change

Merge from sid.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc'
2=== added file '.pc/.version'
3--- .pc/.version 1970-01-01 00:00:00 +0000
4+++ .pc/.version 2011-11-16 01:25:28 +0000
5@@ -0,0 +1,1 @@
6+2
7
8=== added directory '.pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch'
9=== added directory '.pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib'
10=== added file '.pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.c'
11--- .pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.c 1970-01-01 00:00:00 +0000
12+++ .pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.c 2011-11-16 01:25:28 +0000
13@@ -0,0 +1,212 @@
14+/*
15+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
16+ * Copyright (c) 1998-2010 Balázs Scheidler
17+ *
18+ * This library is free software; you can redistribute it and/or
19+ * modify it under the terms of the GNU Lesser General Public
20+ * License as published by the Free Software Foundation; either
21+ * version 2.1 of the License, or (at your option) any later version.
22+ *
23+ * This library is distributed in the hope that it will be useful,
24+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
25+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26+ * Lesser General Public License for more details.
27+ *
28+ * You should have received a copy of the GNU Lesser General Public
29+ * License along with this library; if not, write to the Free Software
30+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31+ *
32+ * As an additional exemption you are allowed to compile & link against the
33+ * OpenSSL libraries as published by the OpenSSL project. See the file
34+ * COPYING for details.
35+ *
36+ */
37+
38+#include "driver.h"
39+#include "logqueue-fifo.h"
40+
41+/* LogDriverPlugin */
42+
43+void
44+log_driver_plugin_free_method(LogDriverPlugin *self)
45+{
46+ g_free(self);
47+}
48+
49+void
50+log_driver_plugin_init_instance(LogDriverPlugin *self)
51+{
52+ self->free_fn = log_driver_plugin_free_method;
53+}
54+
55+/* LogDriver */
56+
57+void
58+log_driver_add_plugin(LogDriver *self, LogDriverPlugin *plugin)
59+{
60+ self->plugins = g_list_append(self->plugins, plugin);
61+}
62+
63+void
64+log_driver_append(LogDriver *self, LogDriver *next)
65+{
66+ if (self->drv_next)
67+ log_pipe_unref(&self->drv_next->super);
68+ self->drv_next = (LogDriver *) log_pipe_ref(&next->super);
69+}
70+
71+gboolean
72+log_driver_init_method(LogPipe *s)
73+{
74+ LogDriver *self = (LogDriver *) s;
75+ gboolean success = TRUE;
76+ GList *l;
77+
78+ for (l = self->plugins; l; l = l->next)
79+ {
80+ if (!log_driver_plugin_attach((LogDriverPlugin *) l->data, self))
81+ success = FALSE;
82+ }
83+ return success;
84+}
85+
86+gboolean
87+log_driver_deinit_method(LogPipe *s)
88+{
89+ LogDriver *self = (LogDriver *) s;
90+ gboolean success = TRUE;
91+ GList *l;
92+
93+ for (l = self->plugins; l; l = l->next)
94+ {
95+ log_driver_plugin_detach((LogDriverPlugin *) l->data, self);
96+ }
97+ return success;
98+}
99+
100+/* NOTE: intentionally static, as only LogSrcDriver or LogDestDriver will derive from LogDriver */
101+static void
102+log_driver_free(LogPipe *s)
103+{
104+ LogDriver *self = (LogDriver *) s;
105+ GList *l;
106+
107+ for (l = self->plugins; l; l = l->next)
108+ {
109+ log_driver_plugin_free((LogDriverPlugin *) l->data);
110+ }
111+ log_pipe_unref(&self->drv_next->super);
112+ self->drv_next = NULL;
113+ if (self->group)
114+ g_free(self->group);
115+ if (self->id)
116+ g_free(self->id);
117+ log_pipe_free_method(s);
118+}
119+
120+/* NOTE: intentionally static, as only LogSrcDriver or LogDestDriver will derive from LogDriver */
121+static void
122+log_driver_init_instance(LogDriver *self)
123+{
124+ log_pipe_init_instance(&self->super);
125+ self->super.free_fn = log_driver_free;
126+ self->super.init = log_driver_init_method;
127+ self->super.deinit = log_driver_deinit_method;
128+}
129+
130+/* LogSrcDriver */
131+
132+void
133+log_src_driver_init_instance(LogSrcDriver *self)
134+{
135+ log_driver_init_instance(&self->super);
136+}
137+
138+void
139+log_src_driver_free(LogPipe *s)
140+{
141+ log_driver_free(s);
142+}
143+
144+/* LogDestDriver */
145+
146+void
147+log_dest_driver_add_queue(LogDestDriver *self, LogQueue *q)
148+{
149+ log_queue_ref(q);
150+ self->queues = g_list_prepend(self->queues, q);
151+}
152+
153+static LogQueue *
154+log_dest_driver_acquire_queue_method(LogDestDriver *self, gchar *persist_name, gpointer user_data)
155+{
156+ GlobalConfig *cfg = log_pipe_get_config(&self->super.super);
157+ LogQueue *queue = NULL;
158+
159+ g_assert(user_data == NULL);
160+
161+ if (persist_name)
162+ queue = cfg_persist_config_fetch(cfg, persist_name);
163+
164+ if (!queue)
165+ {
166+ queue = log_queue_fifo_new(self->log_fifo_size < 0 ? cfg->log_fifo_size : self->log_fifo_size, persist_name);
167+ log_queue_set_throttle(queue, self->throttle);
168+ }
169+ return queue;
170+}
171+
172+static void
173+log_dest_driver_release_queue_method(LogDestDriver *self, LogQueue *q, gpointer user_data)
174+{
175+ GlobalConfig *cfg = log_pipe_get_config(&self->super.super);
176+
177+ if (q->persist_name)
178+ cfg_persist_config_add(cfg, q->persist_name, q, (GDestroyNotify) log_queue_unref, FALSE);
179+ else
180+ log_queue_unref(q);
181+}
182+
183+gboolean
184+log_dest_driver_deinit_method(LogPipe *s)
185+{
186+ LogDestDriver *self = (LogDestDriver *) s;
187+ GList *l;
188+
189+ for (l = self->queues; l; l = l->next)
190+ {
191+ LogQueue *q = (LogQueue *) l->data;
192+
193+ log_dest_driver_release_queue(self, q);
194+ }
195+ g_list_free(self->queues);
196+ self->queues = NULL;
197+
198+ if (!log_driver_deinit_method(s))
199+ return FALSE;
200+ return TRUE;
201+}
202+
203+void
204+log_dest_driver_init_instance(LogDestDriver *self)
205+{
206+ log_driver_init_instance(&self->super);
207+ self->acquire_queue = log_dest_driver_acquire_queue_method;
208+ self->release_queue = log_dest_driver_release_queue_method;
209+ self->log_fifo_size = -1;
210+ self->throttle = 0;
211+}
212+
213+void
214+log_dest_driver_free(LogPipe *s)
215+{
216+ LogDestDriver *self = (LogDestDriver *) s;
217+ GList *l;
218+
219+ for (l = self->queues; l; l = l->next)
220+ {
221+ log_queue_unref((LogQueue *) l->data);
222+ }
223+ g_list_free(self->queues);
224+ log_driver_free(s);
225+}
226
227=== added file '.pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.h'
228--- .pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.h 1970-01-01 00:00:00 +0000
229+++ .pc/LogDestDriver-properly-maintain-self-queues-list-in-acquire-release.patch/lib/driver.h 2011-11-16 01:25:28 +0000
230@@ -0,0 +1,204 @@
231+/*
232+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
233+ * Copyright (c) 1998-2010 Balázs Scheidler
234+ *
235+ * This library is free software; you can redistribute it and/or
236+ * modify it under the terms of the GNU Lesser General Public
237+ * License as published by the Free Software Foundation; either
238+ * version 2.1 of the License, or (at your option) any later version.
239+ *
240+ * This library is distributed in the hope that it will be useful,
241+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
242+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
243+ * Lesser General Public License for more details.
244+ *
245+ * You should have received a copy of the GNU Lesser General Public
246+ * License along with this library; if not, write to the Free Software
247+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
248+ *
249+ * As an additional exemption you are allowed to compile & link against the
250+ * OpenSSL libraries as published by the OpenSSL project. See the file
251+ * COPYING for details.
252+ *
253+ */
254+
255+#ifndef DRIVER_H_INCLUDED
256+#define DRIVER_H_INCLUDED
257+
258+#include "syslog-ng.h"
259+#include "logpipe.h"
260+#include "logqueue.h"
261+#include "cfg.h"
262+
263+/*
264+ * Drivers overview
265+ * ================
266+ *
267+ * In syslog-ng nomenclature a driver is either responsible for handling
268+ * incoming messages (also known as source driver), or to send them out to
269+ * another party (also known as the destination driver). Source drivers are
270+ * created in "source" statements and destination drivers are similarly
271+ * created in "destination" statements.
272+ *
273+ * Drivers are derived from LogPipes, in essence they use the same "queue"
274+ * method to forward messages further down the processing pipeline.
275+ *
276+ * Driver plugins
277+ * ==============
278+ *
279+ * It is possible to change the behaviour of a driver somewhat by adding
280+ * "plugins" to drivers. These plugins basically get a chance to override
281+ * LogDriver virtual methods, change their semantics and possibly rely on
282+ * the original behaviour too. This way, functionalities that are present
283+ * in all destination drivers can easily shared, without having to recode
284+ * the same stuff multiple times.
285+ *
286+ * Driver plugins are activated with the "attach" virtual method, which in
287+ * turn may redirect any of the LogDriver virtual methods to themselves.
288+ * They can even have a "user_data" pointer, so that they can locate their
289+ * associated state.
290+ *
291+ * Multiple plugins can hook into the same method, by saving the original
292+ * address & original user_data value.
293+ *
294+ */
295+
296+/* direction agnostic driver class: LogDriver, see specialized source & destination drivers below */
297+
298+typedef struct _LogDriver LogDriver;
299+typedef struct _LogDriverPlugin LogDriverPlugin;
300+
301+struct _LogDriverPlugin
302+{
303+
304+ /* this function is called when the plugin is attached to a LogDriver
305+ * instance. It should do whatever it is necessary to extend the
306+ * functionality of the driver specified (e.g. hook into various
307+ * methods).
308+ */
309+
310+ gboolean (*attach)(LogDriverPlugin *s, LogDriver *d);
311+ void (*detach)(LogDriverPlugin *s, LogDriver *d);
312+ void (*free_fn)(LogDriverPlugin *s);
313+};
314+
315+static inline gboolean
316+log_driver_plugin_attach(LogDriverPlugin *self, LogDriver *d)
317+{
318+ return self->attach(self, d);
319+}
320+
321+static inline void
322+log_driver_plugin_detach(LogDriverPlugin *self, LogDriver *d)
323+{
324+ if (self->detach)
325+ self->detach(self, d);
326+}
327+
328+static inline void
329+log_driver_plugin_free(LogDriverPlugin *self)
330+{
331+ self->free_fn(self);
332+}
333+
334+void log_driver_plugin_init_instance(LogDriverPlugin *self);
335+void log_driver_plugin_free_method(LogDriverPlugin *self);
336+
337+struct _LogDriver
338+{
339+ LogPipe super;
340+
341+ gboolean optional;
342+ gchar *group;
343+ gchar *id;
344+ GList *plugins;
345+ LogDriver *drv_next;
346+};
347+
348+void log_driver_add_plugin(LogDriver *self, LogDriverPlugin *plugin);
349+void log_driver_append(LogDriver *self, LogDriver *next);
350+
351+/* methods registered to the init/deinit virtual functions */
352+gboolean log_driver_init_method(LogPipe *s);
353+gboolean log_driver_deinit_method(LogPipe *s);
354+
355+
356+/* source driver class: LogSourceDriver */
357+
358+typedef struct _LogSrcDriver LogSrcDriver;
359+
360+struct _LogSrcDriver
361+{
362+ LogDriver super;
363+};
364+
365+static inline gboolean
366+log_src_driver_init_method(LogPipe *s)
367+{
368+ return log_driver_init_method(s);
369+}
370+
371+static inline gboolean
372+log_src_driver_deinit_method(LogPipe *s)
373+{
374+ return log_driver_deinit_method(s);
375+}
376+
377+void log_src_driver_init_instance(LogSrcDriver *self);
378+void log_src_driver_free(LogPipe *s);
379+
380+/* destination driver class: LogDestDriver */
381+
382+typedef struct _LogDestDriver LogDestDriver;
383+
384+struct _LogDestDriver
385+{
386+ LogDriver super;
387+
388+ gpointer acquire_queue_data;
389+ LogQueue *(*acquire_queue)(LogDestDriver *s, gchar *persist_name, gpointer user_data);
390+ gpointer release_queue_data;
391+ void (*release_queue)(LogDestDriver *s, LogQueue *q, gpointer user_data);
392+
393+ /* queues managed by this LogDestDriver, all constructed queues come
394+ * here and are automatically saved into cfg_persist & persist_state. */
395+ GList *queues;
396+
397+ gint log_fifo_size;
398+ gint throttle;
399+};
400+
401+void log_dest_driver_add_queue(LogDestDriver *s, LogQueue *q);
402+
403+static inline LogQueue *
404+log_dest_driver_acquire_queue(LogDestDriver *self, gchar *persist_name)
405+{
406+ LogQueue *q;
407+
408+ {
409+ }
410+
411+ q = self->acquire_queue(self, persist_name, self->acquire_queue_data);
412+ log_dest_driver_add_queue(self, q);
413+ return q;
414+}
415+
416+static inline void
417+log_dest_driver_release_queue(LogDestDriver *self, LogQueue *q)
418+{
419+ self->release_queue(self, q, self->release_queue_data);
420+}
421+
422+static inline gboolean
423+log_dest_driver_init_method(LogPipe *s)
424+{
425+ return log_driver_init_method(s);
426+}
427+
428+gboolean log_dest_driver_deinit_method(LogPipe *s);
429+
430+void log_dest_driver_init_instance(LogDestDriver *self);
431+void log_dest_driver_free(LogPipe *s);
432+
433+
434+#endif
435
436=== added directory '.pc/LogMatcher-fixed-reference-counting.patch'
437=== added directory '.pc/LogMatcher-fixed-reference-counting.patch/lib'
438=== added file '.pc/LogMatcher-fixed-reference-counting.patch/lib/logmatcher.c'
439--- .pc/LogMatcher-fixed-reference-counting.patch/lib/logmatcher.c 1970-01-01 00:00:00 +0000
440+++ .pc/LogMatcher-fixed-reference-counting.patch/lib/logmatcher.c 2011-11-16 01:25:28 +0000
441@@ -0,0 +1,881 @@
442+/*
443+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
444+ * Copyright (c) 1998-2010 Balázs Scheidler
445+ *
446+ * This library is free software; you can redistribute it and/or
447+ * modify it under the terms of the GNU Lesser General Public
448+ * License as published by the Free Software Foundation; either
449+ * version 2.1 of the License, or (at your option) any later version.
450+ *
451+ * This library is distributed in the hope that it will be useful,
452+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
453+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
454+ * Lesser General Public License for more details.
455+ *
456+ * You should have received a copy of the GNU Lesser General Public
457+ * License along with this library; if not, write to the Free Software
458+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
459+ *
460+ * As an additional exemption you are allowed to compile & link against the
461+ * OpenSSL libraries as published by the OpenSSL project. See the file
462+ * COPYING for details.
463+ *
464+ */
465+
466+#include "logmatcher.h"
467+#include "messages.h"
468+#include "cfg.h"
469+#include "misc.h"
470+
471+#include <string.h>
472+#if ENABLE_PCRE
473+#include <pcre.h>
474+#endif
475+
476+static void
477+log_matcher_init(LogMatcher *self, gint type)
478+{
479+ self->type = type;
480+}
481+
482+gint
483+log_matcher_lookup_flag(const gchar* flag)
484+{
485+ if (strcmp(flag, "global") == 0)
486+ return LMF_GLOBAL;
487+ else if (strcmp(flag, "icase") == 0 || strcmp(flag, "ignore-case") == 0 || strcmp(flag, "ignore_case") == 0)
488+ return LMF_ICASE;
489+ else if (strcmp(flag, "newline") == 0)
490+ return LMF_NEWLINE;
491+ else if (strcmp(flag, "unicode") == 0 || strcmp(flag, "utf8") == 0)
492+ return LMF_UTF8;
493+ else if (strcmp(flag, "store-matches") == 0 || strcmp(flag, "store_matches") == 0)
494+ return LMF_STORE_MATCHES;
495+ else if (strcmp(flag, "substring") == 0)
496+ return LMF_SUBSTRING;
497+ else if (strcmp(flag, "prefix") == 0)
498+ return LMF_PREFIX;
499+ else
500+ return 0x0;
501+}
502+
503+typedef struct _LogMatcherPosixRe
504+{
505+ LogMatcher super;
506+ regex_t pattern;
507+} LogMatcherPosixRe;
508+
509+static gboolean
510+log_matcher_posix_re_compile(LogMatcher *s, const gchar *re)
511+{
512+ LogMatcherPosixRe *self = (LogMatcherPosixRe *) s;
513+ gint rc;
514+ const gchar *re_comp = re;
515+ gint flags = REG_EXTENDED;
516+
517+ if (re[0] == '(' && re[1] == '?')
518+ {
519+ gint i;
520+
521+ for (i = 2; re[i] && re[i] != ')'; i++)
522+ {
523+ if (re[i] == 'i')
524+ {
525+ static gboolean warn_written = FALSE;
526+
527+ if (!warn_written)
528+ {
529+ /* deprecated */
530+ msg_warning("WARNING: Your configuration file uses an obsoleted regexp option, please update your configuration",
531+ evt_tag_str("option", "(?i)"),
532+ evt_tag_str("change", "use ignore-case flag instead of (?i)"),
533+ NULL);
534+ warn_written = TRUE;
535+ }
536+
537+ flags |= REG_ICASE;
538+ }
539+ }
540+ if (re[i])
541+ {
542+ re_comp = &re[i + 1];
543+ }
544+ else
545+ {
546+ msg_error("Invalid regexp flags",
547+ evt_tag_str("re", re),
548+ NULL);
549+ return FALSE;
550+ }
551+ }
552+
553+ if (self->super.flags & LMF_ICASE)
554+ flags |= REG_ICASE;
555+ if (self->super.flags & LMF_NEWLINE)
556+ flags |= REG_NEWLINE;
557+ if ((self->super.flags & (LMF_MATCH_ONLY + LMF_STORE_MATCHES)) == LMF_MATCH_ONLY)
558+ flags |= REG_NOSUB;
559+
560+ rc = regcomp(&self->pattern, re_comp, flags);
561+ if (rc)
562+ {
563+ gchar buf[256];
564+
565+ regerror(rc, &self->pattern, buf, sizeof(buf));
566+ msg_error("Error compiling regular expression",
567+ evt_tag_str("re", re),
568+ evt_tag_str("error", buf),
569+ NULL);
570+ return FALSE;
571+ }
572+ return TRUE;
573+}
574+
575+static void
576+log_matcher_posix_re_feed_backrefs(LogMatcher *s, LogMessage *msg, gint value_handle, regmatch_t *matches, const gchar *value)
577+{
578+ gint i;
579+
580+ for (i = 0; i < RE_MAX_MATCHES && matches[i].rm_so != -1; i++)
581+ {
582+ if (value_handle != LM_V_NONE && !log_msg_is_handle_macro(value_handle))
583+ {
584+ log_msg_set_match_indirect(msg, i, value_handle, 0, matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so);
585+ }
586+ else
587+ {
588+ log_msg_set_match(msg, i, &value[matches[i].rm_so], matches[i].rm_eo - matches[i].rm_so);
589+ }
590+ }
591+}
592+
593+static gboolean
594+log_matcher_posix_re_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len)
595+{
596+ LogMatcherPosixRe *self = (LogMatcherPosixRe *) s;
597+ regmatch_t matches[RE_MAX_MATCHES];
598+ gboolean rc;
599+ const gchar *buf;
600+
601+ APPEND_ZERO(buf, value, value_len);
602+ rc = !regexec(&self->pattern, buf, RE_MAX_MATCHES, matches, 0);
603+ if (rc && (s->flags & LMF_STORE_MATCHES))
604+ {
605+ log_matcher_posix_re_feed_backrefs(s, msg, value_handle, matches, value);
606+ }
607+ return rc;
608+}
609+
610+static gchar *
611+log_matcher_posix_re_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length)
612+{
613+ LogMatcherPosixRe *self = (LogMatcherPosixRe *) s;
614+ regmatch_t matches[RE_MAX_MATCHES];
615+ gboolean rc;
616+ GString *new_value = NULL;
617+ gsize current_ofs = 0;
618+ gboolean first_round = TRUE;
619+ gchar *buf;
620+
621+ APPEND_ZERO(buf, value, value_len);
622+
623+ do
624+ {
625+ if (current_ofs == value_len)
626+ break;
627+
628+ rc = !regexec(&self->pattern, buf + current_ofs, RE_MAX_MATCHES, matches, current_ofs > 0 ? REG_NOTBOL : 0);
629+ if (rc)
630+ {
631+ /* start_ofs & end_ofs are relative to the original string */
632+ gsize start_ofs = matches[0].rm_so + current_ofs;
633+ gsize end_ofs = matches[0].rm_eo + current_ofs;
634+
635+ if (start_ofs == end_ofs && !first_round)
636+ {
637+ start_ofs++;
638+ end_ofs++;
639+ }
640+
641+ log_matcher_posix_re_feed_backrefs(s, msg, value_handle, matches, buf + current_ofs);
642+
643+ if (!new_value)
644+ new_value = g_string_sized_new(value_len);
645+
646+ g_string_append_len(new_value, buf + current_ofs, start_ofs - current_ofs);
647+ log_template_append_format(replacement, msg, NULL, LTZ_LOCAL, 0, NULL, new_value);
648+ current_ofs = end_ofs;
649+
650+ if ((self->super.flags & LMF_GLOBAL) == 0)
651+ {
652+ g_string_append_len(new_value, buf + current_ofs, value_len - current_ofs);
653+ break;
654+ }
655+ }
656+ else
657+ {
658+ if (new_value)
659+ {
660+ /* no more matches, append the end of the string */
661+ g_string_append_len(new_value, buf + current_ofs, value_len - current_ofs);
662+ }
663+ }
664+ first_round = FALSE;
665+ }
666+ while (rc && (self->super.flags & LMF_GLOBAL));
667+
668+ if (new_value)
669+ {
670+ if (new_length)
671+ *new_length = new_value->len;
672+ return g_string_free(new_value, FALSE);
673+ }
674+ return NULL;
675+}
676+
677+static void
678+log_matcher_posix_re_free(LogMatcher *s)
679+{
680+ LogMatcherPosixRe *self = (LogMatcherPosixRe *) s;
681+
682+ regfree(&self->pattern);
683+}
684+
685+LogMatcher *
686+log_matcher_posix_re_new(void)
687+{
688+ LogMatcherPosixRe *self = g_new0(LogMatcherPosixRe, 1);
689+
690+ log_matcher_init(&self->super, LMR_POSIX_REGEXP);
691+ self->super.compile = log_matcher_posix_re_compile;
692+ self->super.match = log_matcher_posix_re_match;
693+ self->super.replace = log_matcher_posix_re_replace;
694+ self->super.free_fn = log_matcher_posix_re_free;
695+
696+ if (configuration && configuration->version < 0x0300)
697+ {
698+ static gboolean warn_written = FALSE;
699+
700+ if (!warn_written)
701+ {
702+ msg_warning("WARNING: filters do not store matches in macros by default in 3.0, please update your configuration by using an explicit 'store-matches' flag to achieve that",
703+ NULL);
704+ warn_written = TRUE;
705+ }
706+ self->super.flags = LMF_STORE_MATCHES;
707+ }
708+ return &self->super;
709+}
710+
711+typedef struct _LogMatcherString
712+{
713+ LogMatcher super;
714+ gchar *pattern;
715+ gint pattern_len;
716+} LogMatcherString;
717+
718+static gboolean
719+log_matcher_string_compile(LogMatcher *s, const gchar *pattern)
720+{
721+ LogMatcherString *self = (LogMatcherString *) s;
722+
723+ self->pattern = g_strdup(pattern);
724+ self->pattern_len = strlen(self->pattern);
725+ return TRUE;
726+}
727+
728+static const gchar *
729+log_matcher_string_match_string(LogMatcherString *self, const gchar *value, gsize value_len)
730+{
731+ const gchar *result = NULL;
732+ gboolean match = FALSE;
733+
734+ if (self->pattern_len > value_len)
735+ return NULL;
736+ if (G_LIKELY((self->super.flags & (LMF_SUBSTRING + LMF_PREFIX)) == 0))
737+ {
738+ if (self->super.flags & LMF_ICASE)
739+ match = strncasecmp(value, self->pattern, value_len) == 0;
740+ else
741+ match = strncmp(value, self->pattern, value_len) == 0;
742+ }
743+ else if (self->super.flags & LMF_PREFIX)
744+ {
745+ if (self->super.flags & LMF_ICASE)
746+ match = strncasecmp(value, self->pattern, MIN(value_len, self->pattern_len)) == 0;
747+ else
748+ match = strncmp(value, self->pattern, MIN(value_len, self->pattern_len)) == 0;
749+ }
750+ else if (self->super.flags & LMF_SUBSTRING)
751+ {
752+ if (self->super.flags & LMF_ICASE)
753+ {
754+ gchar *buf;
755+ gchar *res;
756+
757+ APPEND_ZERO(buf, value, value_len);
758+ res = strcasestr(buf, self->pattern);
759+ if (res)
760+ result = value + (res - buf);
761+ }
762+ else
763+ {
764+ result = g_strstr_len(value, value_len, self->pattern);
765+ }
766+ }
767+
768+ if (match && !result)
769+ result = value;
770+ return result;
771+}
772+
773+static gboolean
774+log_matcher_string_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len)
775+{
776+ LogMatcherString *self = (LogMatcherString *) s;
777+
778+ return log_matcher_string_match_string(self, value, value_len) != NULL;
779+}
780+
781+static gchar *
782+log_matcher_string_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length)
783+{
784+ LogMatcherString *self = (LogMatcherString *) s;
785+ GString *new_value = NULL;
786+ gsize current_ofs = 0;
787+ gboolean first_round = TRUE;
788+
789+ if (value_len < 0)
790+ value_len = strlen(value);
791+
792+ const gchar *match;
793+
794+ do
795+ {
796+ if (current_ofs == value_len)
797+ break;
798+
799+ match = log_matcher_string_match_string(self, value + current_ofs, value_len - current_ofs);
800+
801+ if (match != NULL)
802+ {
803+ /* start_ofs & end_ofs are relative to the original string */
804+ gsize start_ofs = match - value;
805+ gsize end_ofs = start_ofs + self->pattern_len;
806+
807+ if (start_ofs == end_ofs && !first_round)
808+ {
809+ start_ofs++;
810+ end_ofs++;
811+ }
812+
813+ if ((s->flags & LMF_STORE_MATCHES))
814+ log_msg_clear_matches(msg);
815+
816+ if (!new_value)
817+ new_value = g_string_sized_new(value_len);
818+
819+ g_string_append_len(new_value, value + current_ofs, start_ofs - current_ofs);
820+ log_template_append_format(replacement, msg, NULL, LTZ_LOCAL, 0, NULL, new_value);
821+ current_ofs = end_ofs;
822+
823+ if ((self->super.flags & LMF_GLOBAL) == 0)
824+ {
825+ g_string_append_len(new_value, value + current_ofs, value_len - current_ofs);
826+ break;
827+ }
828+ }
829+ else
830+ {
831+ if (new_value)
832+ {
833+ /* no more matches, append the end of the string */
834+ g_string_append_len(new_value, value + current_ofs, value_len - current_ofs);
835+ }
836+ }
837+ first_round = FALSE;
838+ }
839+ while (match && (self->super.flags & LMF_GLOBAL));
840+
841+ if (new_value)
842+ {
843+ if (new_length)
844+ *new_length = new_value->len;
845+ return g_string_free(new_value, FALSE);
846+ }
847+ return NULL;
848+}
849+
850+static void
851+log_matcher_string_free(LogMatcher *s)
852+{
853+ LogMatcherString *self = (LogMatcherString *) s;
854+
855+ g_free(self->pattern);
856+}
857+
858+LogMatcher *
859+log_matcher_string_new(void)
860+{
861+ LogMatcherString *self = g_new0(LogMatcherString, 1);
862+
863+ log_matcher_init(&self->super, LMR_STRING);
864+ self->super.compile = log_matcher_string_compile;
865+ self->super.match = log_matcher_string_match;
866+ self->super.replace = log_matcher_string_replace;
867+ self->super.free_fn = log_matcher_string_free;
868+
869+ return &self->super;
870+}
871+
872+typedef struct _LogMatcherGlob
873+{
874+ LogMatcher super;
875+ GPatternSpec *pattern;
876+} LogMatcherGlob;
877+
878+static gboolean
879+log_matcher_glob_compile(LogMatcher *s, const gchar *pattern)
880+{
881+ LogMatcherGlob *self = (LogMatcherGlob *)s;
882+ self->pattern = g_pattern_spec_new(pattern);
883+ return TRUE;
884+}
885+
886+/* GPattern only works with utf8 strings, if the input is not utf8, we risk
887+ * a crash
888+ */
889+static gboolean
890+log_matcher_glob_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len)
891+{
892+ LogMatcherGlob *self = (LogMatcherGlob *) s;
893+
894+ if (G_LIKELY((msg->flags & LF_UTF8) || g_utf8_validate(value, value_len, NULL)))
895+ {
896+ static gboolean warned = FALSE;
897+ gchar *buf;
898+
899+ if (G_UNLIKELY(!warned && (msg->flags & LF_UTF8) == 0))
900+ {
901+ msg_warning("Input is valid utf8, but the log message is not tagged as such, this performs worse than enabling validate-utf8 flag on input",
902+ evt_tag_printf("value", "%.*s", (gint) value_len, value),
903+ NULL);
904+ warned = TRUE;
905+ }
906+ APPEND_ZERO(buf, value, value_len);
907+ return g_pattern_match(self->pattern, value_len, buf, NULL);
908+ }
909+ else
910+ {
911+ msg_warning("Input is not valid utf8, glob match requires utf8 input, thus it never matches in this case",
912+ evt_tag_printf("value", "%.*s", (gint) value_len, value),
913+ NULL);
914+ }
915+ return FALSE;
916+}
917+
918+static void
919+log_matcher_glob_free(LogMatcher *s)
920+{
921+ LogMatcherGlob *self = (LogMatcherGlob*)s;
922+ g_pattern_spec_free(self->pattern);
923+}
924+
925+LogMatcher *
926+log_matcher_glob_new(void)
927+{
928+ LogMatcherGlob *self = g_new0(LogMatcherGlob, 1);
929+
930+ log_matcher_init(&self->super, LMR_GLOB);
931+ self->super.compile = log_matcher_glob_compile;
932+ self->super.match = log_matcher_glob_match;
933+ self->super.replace = NULL;
934+ self->super.free_fn = log_matcher_glob_free;
935+
936+ return &self->super;
937+}
938+
939+#if ENABLE_PCRE
940+
941+/* libpcre support */
942+
943+typedef struct _LogMatcherPcreRe
944+{
945+ LogMatcher super;
946+ pcre *pattern;
947+ pcre_extra *extra;
948+ gint match_options;
949+} LogMatcherPcreRe;
950+
951+static gboolean
952+log_matcher_pcre_re_compile(LogMatcher *s, const gchar *re)
953+{
954+ LogMatcherPcreRe *self = (LogMatcherPcreRe *) s;
955+ gint rc;
956+ const gchar *re_comp = re;
957+ const gchar *errptr;
958+ gint erroffset;
959+ gint flags = 0;
960+
961+ if (self->super.flags & LMF_ICASE)
962+ flags |= PCRE_CASELESS;
963+#ifdef PCRE_NEWLINE_ANYCRLF
964+ if (self->super.flags & LMF_NEWLINE)
965+ flags |= PCRE_NEWLINE_ANYCRLF;
966+#else
967+ if (self->super.flags & LMF_NEWLINE)
968+ msg_warning("syslog-ng was compiled against an old PCRE which doesn't support the 'newline' flag", NULL);
969+#endif
970+ if (self->super.flags & LMF_UTF8)
971+ {
972+ gint support;
973+ flags |= PCRE_UTF8 | PCRE_NO_UTF8_CHECK;
974+ self->match_options |= PCRE_NO_UTF8_CHECK;
975+
976+ pcre_config(PCRE_CONFIG_UTF8, &support);
977+ if (!support)
978+ {
979+ msg_error("PCRE library is compiled without UTF8 support", NULL);
980+ return FALSE;
981+ }
982+
983+ pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &support);
984+ if (!support)
985+ {
986+ msg_error("PCRE library is compiled without UTF8 properties support",NULL);
987+ return FALSE;
988+ }
989+ }
990+
991+ /* complile the regexp */
992+ self->pattern = pcre_compile2(re_comp, flags, &rc, &errptr, &erroffset, NULL);
993+ if (!self->pattern)
994+ {
995+ msg_error("Error while compiling regular expression",
996+ evt_tag_str("regular_expression", re),
997+ evt_tag_str("error_at", &re_comp[erroffset]),
998+ evt_tag_int("error_offset", erroffset),
999+ evt_tag_str("error_message", errptr),
1000+ evt_tag_int("error_code", rc),
1001+ NULL);
1002+ return FALSE;
1003+ }
1004+
1005+ /* optimize regexp */
1006+ self->extra = pcre_study(self->pattern, 0, &errptr);
1007+ if (errptr != NULL)
1008+ {
1009+ msg_error("Error while optimizing regular expression",
1010+ evt_tag_str("regular_expression", re),
1011+ evt_tag_str("error_message", errptr),
1012+ NULL);
1013+ return FALSE;
1014+ }
1015+
1016+ return TRUE;
1017+}
1018+
1019+static void
1020+log_matcher_pcre_re_feed_backrefs(LogMatcher *s, LogMessage *msg, gint value_handle, int *matches, gint match_num, const gchar *value)
1021+{
1022+ gint i;
1023+
1024+ for (i = 0; i < (RE_MAX_MATCHES) && i < match_num; i++)
1025+ {
1026+ if (value_handle != LM_V_NONE && !log_msg_is_handle_macro(value_handle))
1027+ {
1028+ log_msg_set_match_indirect(msg, i, value_handle, 0, matches[2 * i], matches[2 * i + 1] - matches[2 * i]);
1029+ }
1030+ else
1031+ {
1032+ log_msg_set_match(msg, i, &value[matches[2 * i]], matches[2 * i + 1] - matches[2 * i]);
1033+ }
1034+ }
1035+}
1036+
1037+static void
1038+log_matcher_pcre_re_feed_named_substrings(LogMatcher *s, LogMessage *msg, int *matches, const gchar *value)
1039+{
1040+ gchar *name_table = NULL;
1041+ gint i = 0;
1042+ gint namecount = 0;
1043+ gint name_entry_size = 0;
1044+ LogMatcherPcreRe *self = (LogMatcherPcreRe *) s;
1045+
1046+ pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_NAMECOUNT, &namecount);
1047+ if (namecount > 0)
1048+ {
1049+ gchar *tabptr;
1050+ /* Before we can access the substrings, we must extract the table for
1051+ translating names to numbers, and the size of each entry in the table.
1052+ */
1053+ pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_NAMETABLE, &name_table);
1054+ pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_NAMEENTRYSIZE, &name_entry_size);
1055+ /* Now we can scan the table and, for each entry, print the number, the name,
1056+ and the substring itself.
1057+ */
1058+ tabptr = name_table;
1059+ for (i = 0; i < namecount; i++)
1060+ {
1061+ int n = (tabptr[0] << 8) | tabptr[1];
1062+ log_msg_set_value(msg, log_msg_get_value_handle(tabptr + 2), value + matches[2*n], matches[2*n+1] - matches[2*n]);
1063+ tabptr += name_entry_size;
1064+ }
1065+ }
1066+}
1067+
1068+static gboolean
1069+log_matcher_pcre_re_match(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len)
1070+{
1071+ LogMatcherPcreRe *self = (LogMatcherPcreRe *) s;
1072+ gint *matches;
1073+ gsize matches_size;
1074+ gint num_matches;
1075+ gint rc;
1076+
1077+ if (value_len == -1)
1078+ value_len = strlen(value);
1079+
1080+ if (pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_CAPTURECOUNT, &num_matches) < 0)
1081+ g_assert_not_reached();
1082+ if (num_matches > RE_MAX_MATCHES)
1083+ num_matches = RE_MAX_MATCHES;
1084+
1085+ matches_size = 3 * (num_matches + 1);
1086+ matches = g_alloca(matches_size * sizeof(gint));
1087+
1088+ rc = pcre_exec(self->pattern, self->extra,
1089+ value, value_len, 0, self->match_options, matches, matches_size);
1090+ if (rc < 0)
1091+ {
1092+ switch (rc)
1093+ {
1094+ case PCRE_ERROR_NOMATCH:
1095+ break;
1096+
1097+ default:
1098+ /* Handle other special cases */
1099+ msg_error("Error while matching regexp",
1100+ evt_tag_int("error_code", rc),
1101+ NULL);
1102+ break;
1103+ }
1104+ return FALSE;
1105+ }
1106+ if (rc == 0)
1107+ {
1108+ msg_error("Error while storing matching substrings", NULL);
1109+ }
1110+ else
1111+ {
1112+ if ((s->flags & LMF_STORE_MATCHES))
1113+ {
1114+ log_matcher_pcre_re_feed_backrefs(s, msg, value_handle, matches, rc, value);
1115+ log_matcher_pcre_re_feed_named_substrings(s, msg, matches, value);
1116+ }
1117+ }
1118+ return TRUE;
1119+}
1120+
1121+static gchar *
1122+log_matcher_pcre_re_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length)
1123+{
1124+ LogMatcherPcreRe *self = (LogMatcherPcreRe *) s;
1125+ GString *new_value = NULL;
1126+ gint *matches;
1127+ gsize matches_size;
1128+ gint num_matches;
1129+ gint rc;
1130+ gint start_offset, last_offset;
1131+ gint options;
1132+ gboolean last_match_was_empty;
1133+
1134+ if (pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_CAPTURECOUNT, &num_matches) < 0)
1135+ g_assert_not_reached();
1136+ if (num_matches > RE_MAX_MATCHES)
1137+ num_matches = RE_MAX_MATCHES;
1138+
1139+ matches_size = 3 * (num_matches + 1);
1140+ matches = g_alloca(matches_size * sizeof(gint));
1141+
1142+ /* we need zero initialized offsets for the last match as the
1143+ * algorithm tries uses that as the base position */
1144+
1145+ matches[0] = matches[1] = matches[2] = 0;
1146+
1147+ if (value_len == -1)
1148+ value_len = strlen(value);
1149+
1150+ last_offset = start_offset = 0;
1151+ last_match_was_empty = FALSE;
1152+ do
1153+ {
1154+ /* loop over the string, replacing one occurence at a time. */
1155+
1156+ /* NOTE: zero length matches need special care, as we could spin
1157+ * forever otherwise (since the current position wouldn't be
1158+ * advanced).
1159+ *
1160+ * A zero-length match can be as simple as "a*" which will be
1161+ * returned unless PCRE_NOTEMPTY is specified.
1162+ *
1163+ * By supporting zero-length matches, we basically make it
1164+ * possible to insert replacement between each incoming
1165+ * character.
1166+ *
1167+ * For example:
1168+ * pattern: a*
1169+ * replacement: #
1170+ * input: message
1171+ * result: #m#e#s#s#a#g#e#
1172+ *
1173+ * This mimics Perl behaviour.
1174+ */
1175+
1176+ if (last_match_was_empty)
1177+ {
1178+ /* Otherwise, arrange to run another match at the same point
1179+ * to see if a non-empty match can be found.
1180+ */
1181+
1182+ options = PCRE_NOTEMPTY | PCRE_ANCHORED;
1183+ }
1184+ else
1185+ {
1186+ options = 0;
1187+ }
1188+
1189+ rc = pcre_exec(self->pattern, self->extra,
1190+ value, value_len,
1191+ start_offset, (self->match_options | options), matches, matches_size);
1192+ if (rc < 0 && rc != PCRE_ERROR_NOMATCH)
1193+ {
1194+ msg_error("Error while matching regexp",
1195+ evt_tag_int("error_code", rc),
1196+ NULL);
1197+ break;
1198+ }
1199+ else if (rc < 0)
1200+ {
1201+ if ((options & PCRE_NOTEMPTY) == 0)
1202+ {
1203+ /* we didn't match, even when we permitted to match the
1204+ * empty string. Nothing to find here, bail out */
1205+ break;
1206+ }
1207+
1208+ /* we didn't match, quite possibly because the empty match
1209+ * was not permitted. Skip one character in order to avoid
1210+ * infinite loop over the same zero-length match. */
1211+
1212+ start_offset = start_offset + 1;
1213+ /* FIXME: handle complex sequences like utf8 and newline characters */
1214+ last_match_was_empty = FALSE;
1215+ continue;
1216+ }
1217+ else
1218+ {
1219+ /* if the output array was too small, truncate the number of
1220+ captures to RE_MAX_MATCHES */
1221+
1222+ if (rc == 0)
1223+ rc = matches_size / 3;
1224+
1225+ log_matcher_pcre_re_feed_backrefs(s, msg, value_handle, matches, rc, value);
1226+ log_matcher_pcre_re_feed_named_substrings(s, msg, matches, value);
1227+
1228+ if (!new_value)
1229+ new_value = g_string_sized_new(value_len);
1230+ /* append non-matching portion */
1231+ g_string_append_len(new_value, &value[last_offset], matches[0] - last_offset);
1232+ /* replacement */
1233+ log_template_append_format(replacement, msg, NULL, LTZ_LOCAL, 0, NULL, new_value);
1234+
1235+ last_match_was_empty = (matches[0] == matches[1]);
1236+ start_offset = last_offset = matches[1];
1237+ }
1238+ }
1239+ while (self->super.flags & LMF_GLOBAL && start_offset < value_len);
1240+
1241+ if (new_value)
1242+ {
1243+ /* append the last literal */
1244+ g_string_append_len(new_value, &value[last_offset], value_len - last_offset);
1245+ if (new_length)
1246+ *new_length = new_value->len;
1247+ return g_string_free(new_value, FALSE);
1248+ }
1249+ return NULL;
1250+}
1251+
1252+static void
1253+log_matcher_pcre_re_free(LogMatcher *s)
1254+{
1255+ LogMatcherPcreRe *self = (LogMatcherPcreRe *) s;
1256+ pcre_free(self->extra);
1257+ pcre_free(self->pattern);
1258+}
1259+
1260+LogMatcher *
1261+log_matcher_pcre_re_new(void)
1262+{
1263+ LogMatcherPcreRe *self = g_new0(LogMatcherPcreRe, 1);
1264+
1265+ log_matcher_init(&self->super, LMR_PCRE_REGEXP);
1266+ self->super.compile = log_matcher_pcre_re_compile;
1267+ self->super.match = log_matcher_pcre_re_match;
1268+ self->super.replace = log_matcher_pcre_re_replace;
1269+ self->super.free_fn = log_matcher_pcre_re_free;
1270+ return &self->super;
1271+}
1272+#endif
1273+
1274+LogMatcher *
1275+log_matcher_new(const gchar *type)
1276+{
1277+#if ENABLE_PCRE
1278+ if (strcmp(type, "pcre") == 0)
1279+ {
1280+ return log_matcher_pcre_re_new();
1281+ }
1282+ else
1283+#endif
1284+ if (strcmp(type, "posix") == 0)
1285+ {
1286+ return log_matcher_posix_re_new();
1287+ }
1288+ else if (strcmp(type, "string") == 0)
1289+ {
1290+ return log_matcher_string_new();
1291+ }
1292+ else if (strcmp(type, "glob") == 0)
1293+ {
1294+ return log_matcher_glob_new();
1295+ }
1296+ else
1297+ {
1298+ msg_error("Unsupported matcher type, falling back to POSIX regexp",
1299+ evt_tag_str("type", type),
1300+ NULL);
1301+ return log_matcher_posix_re_new();
1302+ }
1303+
1304+}
1305+
1306+LogMatcher *
1307+log_matcher_ref(LogMatcher *s)
1308+{
1309+ s->ref_cnt++;
1310+ return s;
1311+}
1312+
1313+void
1314+log_matcher_unref(LogMatcher *s)
1315+{
1316+ if (--s->ref_cnt)
1317+ {
1318+ if (s->free_fn)
1319+ s->free_fn(s);
1320+ g_free(s);
1321+ }
1322+}
1323
1324=== added directory '.pc/LogQueue-added-keep_on_reload-method.patch'
1325=== added directory '.pc/LogQueue-added-keep_on_reload-method.patch/lib'
1326=== added file '.pc/LogQueue-added-keep_on_reload-method.patch/lib/driver.c'
1327--- .pc/LogQueue-added-keep_on_reload-method.patch/lib/driver.c 1970-01-01 00:00:00 +0000
1328+++ .pc/LogQueue-added-keep_on_reload-method.patch/lib/driver.c 2011-11-16 01:25:28 +0000
1329@@ -0,0 +1,205 @@
1330+/*
1331+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
1332+ * Copyright (c) 1998-2010 Balázs Scheidler
1333+ *
1334+ * This library is free software; you can redistribute it and/or
1335+ * modify it under the terms of the GNU Lesser General Public
1336+ * License as published by the Free Software Foundation; either
1337+ * version 2.1 of the License, or (at your option) any later version.
1338+ *
1339+ * This library is distributed in the hope that it will be useful,
1340+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1341+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1342+ * Lesser General Public License for more details.
1343+ *
1344+ * You should have received a copy of the GNU Lesser General Public
1345+ * License along with this library; if not, write to the Free Software
1346+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1347+ *
1348+ * As an additional exemption you are allowed to compile & link against the
1349+ * OpenSSL libraries as published by the OpenSSL project. See the file
1350+ * COPYING for details.
1351+ *
1352+ */
1353+
1354+#include "driver.h"
1355+#include "logqueue-fifo.h"
1356+
1357+/* LogDriverPlugin */
1358+
1359+void
1360+log_driver_plugin_free_method(LogDriverPlugin *self)
1361+{
1362+ g_free(self);
1363+}
1364+
1365+void
1366+log_driver_plugin_init_instance(LogDriverPlugin *self)
1367+{
1368+ self->free_fn = log_driver_plugin_free_method;
1369+}
1370+
1371+/* LogDriver */
1372+
1373+void
1374+log_driver_add_plugin(LogDriver *self, LogDriverPlugin *plugin)
1375+{
1376+ self->plugins = g_list_append(self->plugins, plugin);
1377+}
1378+
1379+void
1380+log_driver_append(LogDriver *self, LogDriver *next)
1381+{
1382+ if (self->drv_next)
1383+ log_pipe_unref(&self->drv_next->super);
1384+ self->drv_next = (LogDriver *) log_pipe_ref(&next->super);
1385+}
1386+
1387+gboolean
1388+log_driver_init_method(LogPipe *s)
1389+{
1390+ LogDriver *self = (LogDriver *) s;
1391+ gboolean success = TRUE;
1392+ GList *l;
1393+
1394+ for (l = self->plugins; l; l = l->next)
1395+ {
1396+ if (!log_driver_plugin_attach((LogDriverPlugin *) l->data, self))
1397+ success = FALSE;
1398+ }
1399+ return success;
1400+}
1401+
1402+gboolean
1403+log_driver_deinit_method(LogPipe *s)
1404+{
1405+ LogDriver *self = (LogDriver *) s;
1406+ gboolean success = TRUE;
1407+ GList *l;
1408+
1409+ for (l = self->plugins; l; l = l->next)
1410+ {
1411+ log_driver_plugin_detach((LogDriverPlugin *) l->data, self);
1412+ }
1413+ return success;
1414+}
1415+
1416+/* NOTE: intentionally static, as only LogSrcDriver or LogDestDriver will derive from LogDriver */
1417+static void
1418+log_driver_free(LogPipe *s)
1419+{
1420+ LogDriver *self = (LogDriver *) s;
1421+ GList *l;
1422+
1423+ for (l = self->plugins; l; l = l->next)
1424+ {
1425+ log_driver_plugin_free((LogDriverPlugin *) l->data);
1426+ }
1427+ log_pipe_unref(&self->drv_next->super);
1428+ self->drv_next = NULL;
1429+ if (self->group)
1430+ g_free(self->group);
1431+ if (self->id)
1432+ g_free(self->id);
1433+ log_pipe_free_method(s);
1434+}
1435+
1436+/* NOTE: intentionally static, as only LogSrcDriver or LogDestDriver will derive from LogDriver */
1437+static void
1438+log_driver_init_instance(LogDriver *self)
1439+{
1440+ log_pipe_init_instance(&self->super);
1441+ self->super.free_fn = log_driver_free;
1442+ self->super.init = log_driver_init_method;
1443+ self->super.deinit = log_driver_deinit_method;
1444+}
1445+
1446+/* LogSrcDriver */
1447+
1448+void
1449+log_src_driver_init_instance(LogSrcDriver *self)
1450+{
1451+ log_driver_init_instance(&self->super);
1452+}
1453+
1454+void
1455+log_src_driver_free(LogPipe *s)
1456+{
1457+ log_driver_free(s);
1458+}
1459+
1460+/* LogDestDriver */
1461+
1462+/* returns a reference */
1463+static LogQueue *
1464+log_dest_driver_acquire_queue_method(LogDestDriver *self, gchar *persist_name, gpointer user_data)
1465+{
1466+ GlobalConfig *cfg = log_pipe_get_config(&self->super.super);
1467+ LogQueue *queue = NULL;
1468+
1469+ g_assert(user_data == NULL);
1470+
1471+ if (persist_name)
1472+ queue = cfg_persist_config_fetch(cfg, persist_name);
1473+
1474+ if (!queue)
1475+ {
1476+ queue = log_queue_fifo_new(self->log_fifo_size < 0 ? cfg->log_fifo_size : self->log_fifo_size, persist_name);
1477+ log_queue_set_throttle(queue, self->throttle);
1478+ }
1479+ return queue;
1480+}
1481+
1482+static void
1483+log_dest_driver_release_queue_method(LogDestDriver *self, LogQueue *q, gpointer user_data)
1484+{
1485+ GlobalConfig *cfg = log_pipe_get_config(&self->super.super);
1486+
1487+ if (q->persist_name)
1488+ cfg_persist_config_add(cfg, q->persist_name, q, (GDestroyNotify) log_queue_unref, FALSE);
1489+ else
1490+ log_queue_unref(q);
1491+}
1492+
1493+gboolean
1494+log_dest_driver_deinit_method(LogPipe *s)
1495+{
1496+ LogDestDriver *self = (LogDestDriver *) s;
1497+ GList *l;
1498+
1499+ for (l = self->queues; l; l = l->next)
1500+ {
1501+ LogQueue *q = (LogQueue *) l->data;
1502+
1503+ log_dest_driver_release_queue(self, q);
1504+ }
1505+ g_assert(self->queues == NULL);
1506+
1507+ if (!log_driver_deinit_method(s))
1508+ return FALSE;
1509+ return TRUE;
1510+}
1511+
1512+void
1513+log_dest_driver_init_instance(LogDestDriver *self)
1514+{
1515+ log_driver_init_instance(&self->super);
1516+ self->acquire_queue = log_dest_driver_acquire_queue_method;
1517+ self->release_queue = log_dest_driver_release_queue_method;
1518+ self->log_fifo_size = -1;
1519+ self->throttle = 0;
1520+}
1521+
1522+void
1523+log_dest_driver_free(LogPipe *s)
1524+{
1525+ LogDestDriver *self = (LogDestDriver *) s;
1526+ GList *l;
1527+
1528+ for (l = self->queues; l; l = l->next)
1529+ {
1530+ log_queue_unref((LogQueue *) l->data);
1531+ }
1532+ g_list_free(self->queues);
1533+ log_driver_free(s);
1534+}
1535
1536=== added file '.pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue-fifo.c'
1537--- .pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue-fifo.c 1970-01-01 00:00:00 +0000
1538+++ .pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue-fifo.c 2011-11-16 01:25:28 +0000
1539@@ -0,0 +1,463 @@
1540+/*
1541+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
1542+ * Copyright (c) 1998-2010 Balázs Scheidler
1543+ *
1544+ * This library is free software; you can redistribute it and/or
1545+ * modify it under the terms of the GNU Lesser General Public
1546+ * License as published by the Free Software Foundation; either
1547+ * version 2.1 of the License, or (at your option) any later version.
1548+ *
1549+ * This library is distributed in the hope that it will be useful,
1550+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1551+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1552+ * Lesser General Public License for more details.
1553+ *
1554+ * You should have received a copy of the GNU Lesser General Public
1555+ * License along with this library; if not, write to the Free Software
1556+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1557+ *
1558+ * As an additional exemption you are allowed to compile & link against the
1559+ * OpenSSL libraries as published by the OpenSSL project. See the file
1560+ * COPYING for details.
1561+ *
1562+ */
1563+
1564+#include "logqueue.h"
1565+#include "logpipe.h"
1566+#include "messages.h"
1567+#include "serialize.h"
1568+#include "stats.h"
1569+#include "mainloop.h"
1570+
1571+#include <sys/types.h>
1572+#include <sys/stat.h>
1573+#include <fcntl.h>
1574+#include <unistd.h>
1575+#include <string.h>
1576+#include <iv_thread.h>
1577+
1578+/*
1579+ * LogFifo is a scalable first-in-first-output queue implementation, that:
1580+ *
1581+ * - has a per-thread, unlocked input queue where threads can put their items
1582+ *
1583+ * - has a locked wait-queue where items go once the per-thread input
1584+ * would be overflown or if the input thread goes to sleep (e.g. one
1585+ * lock acquisition per a longer period)
1586+ *
1587+ * - has an unlocked output queue where items from the wait queue go, once
1588+ * it becomes depleted.
1589+ *
1590+ * This means that items flow in this sequence from one list to the next:
1591+ *
1592+ * input queue (per-thread) -> wait queue (locked) -> output queue (single-threaded)
1593+ *
1594+ * Fastpath is:
1595+ * - input threads putting elements on their per-thread queue (lockless)
1596+ * - output threads removing elements from the output queue (lockless)
1597+ *
1598+ * Slowpath:
1599+ * - input queue is overflown (or the input thread goes to sleep), wait
1600+ * queue mutex is grabbed, all elements are put to the wait queue.
1601+ *
1602+ * - output queue is depleted, wait queue mutex is grabbed, all elements
1603+ * on the wait queue is put to the output queue
1604+ *
1605+ * Threading assumptions:
1606+ * - the head of the queue is only manipulated from the output thread
1607+ * - the tail of the queue is only manipulated from the input threads
1608+ *
1609+ */
1610+
1611+
1612+typedef struct _LogQueueFifo
1613+{
1614+ LogQueue super;
1615+
1616+ /* scalable qoverflow implementation */
1617+ struct list_head qoverflow_output;
1618+ struct list_head qoverflow_wait;
1619+ gint qoverflow_wait_len;
1620+ gint qoverflow_output_len;
1621+ gint qoverflow_size; /* in number of elements */
1622+
1623+ struct list_head qbacklog; /* entries that were sent but not acked yet */
1624+ gint qbacklog_len;
1625+
1626+ struct
1627+ {
1628+ struct list_head items;
1629+ MainLoopIOWorkerFinishCallback cb;
1630+ guint16 len;
1631+ guint16 finish_cb_registered;
1632+ } qoverflow_input[0];
1633+} LogQueueFifo;
1634+
1635+/* NOTE: this is inherently racy, unless protected by LogQueue->lock */
1636+static gint64
1637+log_queue_fifo_get_length(LogQueue *s)
1638+{
1639+ LogQueueFifo *self = (LogQueueFifo *) s;
1640+
1641+ return self->qoverflow_wait_len + self->qoverflow_output_len;
1642+}
1643+
1644+/* move items from the per-thread input queue to the lock-protected "wait" queue */
1645+static void
1646+log_queue_fifo_move_input_unlocked(LogQueueFifo *self, gint thread_id)
1647+{
1648+ if (log_queue_fifo_get_length(&self->super) + self->qoverflow_input[thread_id].len > self->qoverflow_size)
1649+ {
1650+ /* slow path, the input thread's queue would overflow the queue, let's drop some messages */
1651+
1652+ LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
1653+ gint n = self->qoverflow_input[thread_id].len - (self->qoverflow_size - log_queue_fifo_get_length(&self->super));
1654+ gint i;
1655+
1656+ for (i = 0; i < n; i++)
1657+ {
1658+ LogMessageQueueNode *node = list_entry(self->qoverflow_input[thread_id].items.next, LogMessageQueueNode, list);
1659+ LogMessage *msg = node->msg;
1660+
1661+ list_del(&node->list);
1662+ self->qoverflow_input[thread_id].len--;
1663+ path_options.ack_needed = node->ack_needed;
1664+ stats_counter_inc(self->super.dropped_messages);
1665+ log_msg_free_queue_node(node);
1666+ log_msg_drop(msg, &path_options);
1667+ }
1668+ msg_debug("Destination queue full, dropping messages",
1669+ evt_tag_int("queue_len", log_queue_fifo_get_length(&self->super)),
1670+ evt_tag_int("log_fifo_size", self->qoverflow_size),
1671+ evt_tag_int("count", n),
1672+ NULL);
1673+ }
1674+ stats_counter_add(self->super.stored_messages, self->qoverflow_input[thread_id].len);
1675+ list_splice_tail_init(&self->qoverflow_input[thread_id].items, &self->qoverflow_wait);
1676+ self->qoverflow_wait_len += self->qoverflow_input[thread_id].len;
1677+ self->qoverflow_input[thread_id].len = 0;
1678+}
1679+
1680+/* move items from the per-thread input queue to the lock-protected
1681+ * "wait" queue, but grabbing locks first. This is registered as a
1682+ * callback to be called when the input worker thread finishes its
1683+ * job.
1684+ */
1685+static gpointer
1686+log_queue_fifo_move_input(gpointer user_data)
1687+{
1688+ LogQueueFifo *self = (LogQueueFifo *) user_data;
1689+ gint thread_id;
1690+
1691+ thread_id = main_loop_io_worker_thread_id();
1692+
1693+ g_assert(thread_id >= 0);
1694+
1695+ g_static_mutex_lock(&self->super.lock);
1696+ log_queue_fifo_move_input_unlocked(self, thread_id);
1697+ log_queue_push_notify(&self->super);
1698+ g_static_mutex_unlock(&self->super.lock);
1699+ self->qoverflow_input[thread_id].finish_cb_registered = FALSE;
1700+ return NULL;
1701+}
1702+
1703+/**
1704+ * Assumed to be called from one of the input threads. If the thread_id
1705+ * cannot be determined, the item is put directly in the wait queue.
1706+ *
1707+ * Puts the message to the queue, and logs an error if it caused the
1708+ * queue to be full.
1709+ *
1710+ * It attempts to put the item to the per-thread input queue.
1711+ **/
1712+static void
1713+log_queue_fifo_push_tail(LogQueue *s, LogMessage *msg, const LogPathOptions *path_options)
1714+{
1715+ LogQueueFifo *self = (LogQueueFifo *) s;
1716+ gint thread_id;
1717+ LogMessageQueueNode *node;
1718+
1719+ thread_id = main_loop_io_worker_thread_id();
1720+
1721+ g_assert(thread_id < 0 || log_queue_max_threads > thread_id);
1722+
1723+ /* NOTE: we don't use high-water marks for now, as log_fetch_limit
1724+ * limits the number of items placed on the per-thread input queue
1725+ * anyway, and any sane number decreased the performance measurably.
1726+ *
1727+ * This means that per-thread input queues contain _all_ items that
1728+ * a single poll iteration produces. And once the reader is finished
1729+ * (either because the input is depleted or because of
1730+ * log_fetch_limit / window_size) the whole bunch is propagated to
1731+ * the "wait" queue.
1732+ */
1733+
1734+ if (thread_id >= 0) {
1735+ /* fastpath, use per-thread input FIFOs */
1736+ if (!self->qoverflow_input[thread_id].finish_cb_registered)
1737+ {
1738+ /* this is the first item in the input FIFO, register a finish
1739+ * callback to make sure it gets moved to the wait_queue if the
1740+ * input thread finishes */
1741+
1742+ main_loop_io_worker_register_finish_callback(&self->qoverflow_input[thread_id].cb);
1743+ self->qoverflow_input[thread_id].finish_cb_registered = TRUE;
1744+ }
1745+
1746+ node = log_msg_alloc_queue_node(msg, path_options);
1747+ list_add_tail(&node->list, &self->qoverflow_input[thread_id].items);
1748+ self->qoverflow_input[thread_id].len++;
1749+ log_msg_unref(msg);
1750+ return;
1751+ }
1752+
1753+ /* slow path, put the pending item and the whole input queue to the wait_queue */
1754+
1755+ g_static_mutex_lock(&self->super.lock);
1756+
1757+ if (thread_id >= 0)
1758+ log_queue_fifo_move_input_unlocked(self, thread_id);
1759+
1760+ if (log_queue_fifo_get_length(s) < self->qoverflow_size)
1761+ {
1762+ node = log_msg_alloc_queue_node(msg, path_options);
1763+
1764+ list_add_tail(&node->list, &self->qoverflow_wait);
1765+ self->qoverflow_wait_len++;
1766+ log_queue_push_notify(&self->super);
1767+
1768+ stats_counter_inc(self->super.stored_messages);
1769+ g_static_mutex_unlock(&self->super.lock);
1770+
1771+ log_msg_unref(msg);
1772+ }
1773+ else
1774+ {
1775+ stats_counter_inc(self->super.dropped_messages);
1776+ g_static_mutex_unlock(&self->super.lock);
1777+ log_msg_drop(msg, path_options);
1778+
1779+ msg_debug("Destination queue full, dropping message",
1780+ evt_tag_int("queue_len", log_queue_fifo_get_length(&self->super)),
1781+ evt_tag_int("log_fifo_size", self->qoverflow_size),
1782+ NULL);
1783+ }
1784+ return;
1785+}
1786+
1787+/*
1788+ * Put an item back to the front of the queue.
1789+ *
1790+ * This is assumed to be called only from the output thread.
1791+ */
1792+static void
1793+log_queue_fifo_push_head(LogQueue *s, LogMessage *msg, const LogPathOptions *path_options)
1794+{
1795+ LogQueueFifo *self = (LogQueueFifo *) s;
1796+ LogMessageQueueNode *node;
1797+
1798+ /* we don't check limits when putting items "in-front", as it
1799+ * normally happens when we start processing an item, but at the end
1800+ * can't deliver it. No checks, no drops either. */
1801+
1802+ log_queue_assert_output_thread(s);
1803+
1804+ node = log_msg_alloc_dynamic_queue_node(msg, path_options);
1805+ list_add(&node->list, &self->qoverflow_output);
1806+ self->qoverflow_output_len++;
1807+
1808+ stats_counter_inc(self->super.stored_messages);
1809+}
1810+
1811+/*
1812+ * Can only run from the output thread.
1813+ */
1814+static gboolean
1815+log_queue_fifo_pop_head(LogQueue *s, LogMessage **msg, LogPathOptions *path_options, gboolean push_to_backlog, gboolean ignore_throttle)
1816+{
1817+ LogQueueFifo *self = (LogQueueFifo *) s;
1818+ LogMessageQueueNode *node;
1819+
1820+ log_queue_assert_output_thread(s);
1821+
1822+ if (!ignore_throttle && self->super.throttle && self->super.throttle_buckets == 0)
1823+ {
1824+ return FALSE;
1825+ }
1826+
1827+ if (self->qoverflow_output_len == 0)
1828+ {
1829+ /* slow path, output queue is empty, get some elements from the wait queue */
1830+ g_static_mutex_lock(&self->super.lock);
1831+ list_splice_tail_init(&self->qoverflow_wait, &self->qoverflow_output);
1832+ self->qoverflow_output_len = self->qoverflow_wait_len;
1833+ self->qoverflow_wait_len = 0;
1834+ g_static_mutex_unlock(&self->super.lock);
1835+ }
1836+
1837+ if (self->qoverflow_output_len > 0)
1838+ {
1839+ node = list_entry(self->qoverflow_output.next, LogMessageQueueNode, list);
1840+
1841+ *msg = node->msg;
1842+ path_options->ack_needed = node->ack_needed;
1843+ self->qoverflow_output_len--;
1844+ if (!push_to_backlog)
1845+ {
1846+ list_del(&node->list);
1847+ log_msg_free_queue_node(node);
1848+ }
1849+ else
1850+ {
1851+ list_del_init(&node->list);
1852+ }
1853+ }
1854+ else
1855+ {
1856+ /* no items either on the wait queue nor the output queue.
1857+ *
1858+ * NOTE: the input queues may contain items even in this case,
1859+ * however we don't touch them here, they'll be migrated to the
1860+ * wait_queue once the input threads finish their processing (or
1861+ * the high watermark is reached). Also, they are unlocked, so
1862+ * no way to touch them safely.
1863+ */
1864+ return FALSE;
1865+ }
1866+ stats_counter_dec(self->super.stored_messages);
1867+
1868+ if (push_to_backlog)
1869+ {
1870+ log_msg_ref(*msg);
1871+ list_add_tail(&node->list, &self->qbacklog);
1872+ self->qbacklog_len++;
1873+ }
1874+ if (!ignore_throttle)
1875+ {
1876+ self->super.throttle_buckets--;
1877+ }
1878+
1879+ return TRUE;
1880+}
1881+
1882+/*
1883+ * Can only run from the output thread.
1884+ */
1885+static void
1886+log_queue_fifo_ack_backlog(LogQueue *s, gint n)
1887+{
1888+ LogQueueFifo *self = (LogQueueFifo *) s;
1889+ LogMessage *msg;
1890+ LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
1891+ gint i;
1892+
1893+ log_queue_assert_output_thread(s);
1894+
1895+ for (i = 0; i < n && self->qbacklog_len > 0; i++)
1896+ {
1897+ LogMessageQueueNode *node;
1898+
1899+ node = list_entry(self->qbacklog.next, LogMessageQueueNode, list);
1900+ msg = node->msg;
1901+ path_options.ack_needed = node->ack_needed;
1902+
1903+ list_del(&node->list);
1904+ log_msg_free_queue_node(node);
1905+ self->qbacklog_len--;
1906+
1907+ log_msg_ack(msg, &path_options);
1908+ log_msg_unref(msg);
1909+ }
1910+}
1911+
1912+
1913+/*
1914+ * log_queue_rewind_backlog:
1915+ *
1916+ * Move items on our backlog back to our qoverflow queue. Please note that this
1917+ * function does not really care about qoverflow size, it has to put the backlog
1918+ * somewhere. The backlog is emptied as that will be filled if we send the
1919+ * items again.
1920+ *
1921+ * NOTE: this is assumed to be called from the output thread.
1922+ */
1923+static void
1924+log_queue_fifo_rewind_backlog(LogQueue *s)
1925+{
1926+ LogQueueFifo *self = (LogQueueFifo *) s;
1927+
1928+ log_queue_assert_output_thread(s);
1929+
1930+ list_splice_tail_init(&self->qbacklog, &self->qoverflow_output);
1931+ self->qoverflow_output_len += self->qbacklog_len;
1932+ stats_counter_add(self->super.stored_messages, self->qbacklog_len);
1933+ self->qbacklog_len = 0;
1934+}
1935+
1936+static void
1937+log_queue_fifo_free_queue(struct list_head *q)
1938+{
1939+ while (!list_empty(q))
1940+ {
1941+ LogMessageQueueNode *node;
1942+ LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
1943+ LogMessage *msg;
1944+
1945+ node = list_entry(q->next, LogMessageQueueNode, list);
1946+ list_del(&node->list);
1947+
1948+ path_options.ack_needed = node->ack_needed;
1949+ msg = node->msg;
1950+ log_msg_free_queue_node(node);
1951+ log_msg_ack(msg, &path_options);
1952+ log_msg_unref(msg);
1953+ }
1954+}
1955+
1956+static void
1957+log_queue_fifo_free(LogQueue *s)
1958+{
1959+ LogQueueFifo *self = (LogQueueFifo *) s;
1960+ gint i;
1961+
1962+ for (i = 0; i < log_queue_max_threads; i++)
1963+ log_queue_fifo_free_queue(&self->qoverflow_input[i].items);
1964+
1965+ log_queue_fifo_free_queue(&self->qoverflow_wait);
1966+ log_queue_fifo_free_queue(&self->qoverflow_output);
1967+ log_queue_fifo_free_queue(&self->qbacklog);
1968+ log_queue_free_method(s);
1969+}
1970+
1971+LogQueue *
1972+log_queue_fifo_new(gint qoverflow_size, const gchar *persist_name)
1973+{
1974+ LogQueueFifo *self;
1975+ gint i;
1976+
1977+ self = g_malloc0(sizeof(LogQueueFifo) + log_queue_max_threads * sizeof(self->qoverflow_input[0]));
1978+
1979+ log_queue_init_instance(&self->super, persist_name);
1980+ self->super.get_length = log_queue_fifo_get_length;
1981+ self->super.push_tail = log_queue_fifo_push_tail;
1982+ self->super.push_head = log_queue_fifo_push_head;
1983+ self->super.pop_head = log_queue_fifo_pop_head;
1984+ self->super.ack_backlog = log_queue_fifo_ack_backlog;
1985+ self->super.rewind_backlog = log_queue_fifo_rewind_backlog;
1986+
1987+ self->super.free_fn = log_queue_fifo_free;
1988+
1989+ for (i = 0; i < log_queue_max_threads; i++)
1990+ {
1991+ INIT_LIST_HEAD(&self->qoverflow_input[i].items);
1992+ main_loop_io_worker_finish_callback_init(&self->qoverflow_input[i].cb);
1993+ self->qoverflow_input[i].cb.user_data = self;
1994+ self->qoverflow_input[i].cb.func = log_queue_fifo_move_input;
1995+ }
1996+ INIT_LIST_HEAD(&self->qoverflow_wait);
1997+ INIT_LIST_HEAD(&self->qoverflow_output);
1998+ INIT_LIST_HEAD(&self->qbacklog);
1999+
2000+ self->qoverflow_size = qoverflow_size;
2001+ return &self->super;
2002+}
2003
2004=== added file '.pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue.h'
2005--- .pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue.h 1970-01-01 00:00:00 +0000
2006+++ .pc/LogQueue-added-keep_on_reload-method.patch/lib/logqueue.h 2011-11-16 01:25:28 +0000
2007@@ -0,0 +1,150 @@
2008+/*
2009+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
2010+ * Copyright (c) 1998-2010 Balázs Scheidler
2011+ *
2012+ * This library is free software; you can redistribute it and/or
2013+ * modify it under the terms of the GNU Lesser General Public
2014+ * License as published by the Free Software Foundation; either
2015+ * version 2.1 of the License, or (at your option) any later version.
2016+ *
2017+ * This library is distributed in the hope that it will be useful,
2018+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2019+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2020+ * Lesser General Public License for more details.
2021+ *
2022+ * You should have received a copy of the GNU Lesser General Public
2023+ * License along with this library; if not, write to the Free Software
2024+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2025+ *
2026+ * As an additional exemption you are allowed to compile & link against the
2027+ * OpenSSL libraries as published by the OpenSSL project. See the file
2028+ * COPYING for details.
2029+ *
2030+ */
2031+
2032+#ifndef LOGQUEUE_H_INCLUDED
2033+#define LOGQUEUE_H_INCLUDED
2034+
2035+#include "logmsg.h"
2036+#include "stats.h"
2037+
2038+extern gint log_queue_max_threads;
2039+
2040+typedef void (*LogQueuePushNotifyFunc)(gpointer user_data);
2041+
2042+typedef struct _LogQueue LogQueue;
2043+
2044+struct _LogQueue
2045+{
2046+ /* this object is reference counted, but it is _not_ thread safe to
2047+ acquire/release references in code executing in parallel */
2048+ gint ref_cnt;
2049+ gint throttle;
2050+ gint throttle_buckets;
2051+ GTimeVal last_throttle_check;
2052+
2053+ gchar *persist_name;
2054+ StatsCounterItem *stored_messages;
2055+ StatsCounterItem *dropped_messages;
2056+
2057+ GStaticMutex lock;
2058+ gint parallel_push_notify_limit;
2059+ LogQueuePushNotifyFunc parallel_push_notify;
2060+ gpointer parallel_push_data;
2061+ GDestroyNotify parallel_push_data_destroy;
2062+
2063+ /* queue management */
2064+ gint64 (*get_length)(LogQueue *self);
2065+ void (*push_tail)(LogQueue *self, LogMessage *msg, const LogPathOptions *path_options);
2066+ void (*push_head)(LogQueue *self, LogMessage *msg, const LogPathOptions *path_options);
2067+ gboolean (*pop_head)(LogQueue *self, LogMessage **msg, LogPathOptions *path_options, gboolean push_to_backlog, gboolean ignore_throttle);
2068+ void (*ack_backlog)(LogQueue *self, gint n);
2069+ void (*rewind_backlog)(LogQueue *self);
2070+
2071+ void (*free_fn)(LogQueue *self);
2072+};
2073+
2074+static inline gint64
2075+log_queue_get_length(LogQueue *self)
2076+{
2077+ return self->get_length(self);
2078+}
2079+
2080+static inline void
2081+log_queue_push_tail(LogQueue *self, LogMessage *msg, const LogPathOptions *path_options)
2082+{
2083+ self->push_tail(self, msg, path_options);
2084+}
2085+
2086+static inline void
2087+log_queue_push_head(LogQueue *self, LogMessage *msg, const LogPathOptions *path_options)
2088+{
2089+ self->push_head(self, msg, path_options);
2090+}
2091+
2092+static inline gboolean
2093+log_queue_pop_head(LogQueue *self, LogMessage **msg, LogPathOptions *path_options, gboolean push_to_backlog, gboolean ignore_throttle)
2094+{
2095+ return self->pop_head(self, msg, path_options, push_to_backlog, ignore_throttle);
2096+}
2097+
2098+static inline void
2099+log_queue_rewind_backlog(LogQueue *self)
2100+{
2101+ return self->rewind_backlog(self);
2102+}
2103+
2104+static inline void
2105+log_queue_ack_backlog(LogQueue *self, gint n)
2106+{
2107+ return self->ack_backlog(self, n);
2108+}
2109+
2110+static inline LogQueue *
2111+log_queue_ref(LogQueue *self)
2112+{
2113+ self->ref_cnt++;
2114+ return self;
2115+}
2116+
2117+static inline void
2118+log_queue_unref(LogQueue *self)
2119+{
2120+ if (--self->ref_cnt == 0)
2121+ self->free_fn(self);
2122+}
2123+
2124+static inline void
2125+log_queue_set_throttle(LogQueue *self, gint throttle)
2126+{
2127+ self->throttle = throttle;
2128+ self->throttle_buckets = throttle;
2129+}
2130+
2131+/*
2132+ * This assertion marks the assumption that a given function is
2133+ * running solely from the output thread. It _will not_ catch all
2134+ * invalid invocations, but will most probably catch it sooner rather
2135+ * than later.
2136+ *
2137+ * The check it performs (parallel_push_notify is NULL) means that
2138+ * there's no current parallel_push_notify callbacks pending.
2139+ *
2140+ * Since parallel_push_notify is set to non-NULL by the output thread
2141+ * when waiting for elements to arrive (e.g. when going to sleep), it
2142+ * is quite certain that if we are NOT in the output thread, that will
2143+ * be set.
2144+ */
2145+#define log_queue_assert_output_thread(self) g_assert(self->parallel_push_notify == NULL)
2146+
2147+void log_queue_push_notify(LogQueue *self);
2148+void log_queue_reset_parallel_push(LogQueue *self);
2149+void log_queue_set_parallel_push(LogQueue *self, gint notify_limit, LogQueuePushNotifyFunc parallel_push_notify, gpointer user_data, GDestroyNotify user_data_destroy);
2150+gboolean log_queue_check_items(LogQueue *self, gint batch_items, gboolean *partial_batch, gint *timeout, LogQueuePushNotifyFunc parallel_push_notify, gpointer user_data, GDestroyNotify user_data_destroy);
2151+void log_queue_set_counters(LogQueue *self, StatsCounterItem *stored_messages, StatsCounterItem *dropped_messages);
2152+void log_queue_init_instance(LogQueue *self, const gchar *persist_name);
2153+void log_queue_free_method(LogQueue *self);
2154+
2155+void log_queue_set_max_threads(gint max_threads);
2156+
2157+#endif
2158
2159=== added directory '.pc/LogWriter-introduce-log_writer_get_queue-method.patch'
2160=== added directory '.pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib'
2161=== added file '.pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.c'
2162--- .pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.c 1970-01-01 00:00:00 +0000
2163+++ .pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.c 2011-11-16 01:25:28 +0000
2164@@ -0,0 +1,1403 @@
2165+/*
2166+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
2167+ * Copyright (c) 1998-2010 Balázs Scheidler
2168+ *
2169+ * This library is free software; you can redistribute it and/or
2170+ * modify it under the terms of the GNU Lesser General Public
2171+ * License as published by the Free Software Foundation; either
2172+ * version 2.1 of the License, or (at your option) any later version.
2173+ *
2174+ * This library is distributed in the hope that it will be useful,
2175+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2176+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2177+ * Lesser General Public License for more details.
2178+ *
2179+ * You should have received a copy of the GNU Lesser General Public
2180+ * License along with this library; if not, write to the Free Software
2181+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2182+ *
2183+ * As an additional exemption you are allowed to compile & link against the
2184+ * OpenSSL libraries as published by the OpenSSL project. See the file
2185+ * COPYING for details.
2186+ *
2187+ */
2188+
2189+#include "logwriter.h"
2190+#include "messages.h"
2191+#include "stats.h"
2192+#include "misc.h"
2193+#include "mainloop.h"
2194+#include "str-format.h"
2195+
2196+#include <unistd.h>
2197+#include <assert.h>
2198+#include <string.h>
2199+#include <stdlib.h>
2200+#include <sys/stat.h>
2201+#include <unistd.h>
2202+#include <iv.h>
2203+#include <iv_event.h>
2204+#include <iv_work.h>
2205+
2206+typedef enum
2207+{
2208+ /* flush modes */
2209+
2210+ /* business as usual, flush when the buffer is full */
2211+ LW_FLUSH_NORMAL,
2212+ /* flush the buffer immediately please */
2213+ LW_FLUSH_BUFFER,
2214+ /* pull off any queued items, at maximum speed, even ignoring throttle, and flush the buffer too */
2215+ LW_FLUSH_QUEUE,
2216+} LogWriterFlushMode;
2217+
2218+struct _LogWriter
2219+{
2220+ LogPipe super;
2221+ LogQueue *queue;
2222+ guint32 flags:31;
2223+ gint32 seq_num;
2224+ StatsCounterItem *dropped_messages;
2225+ StatsCounterItem *suppressed_messages;
2226+ StatsCounterItem *processed_messages;
2227+ StatsCounterItem *stored_messages;
2228+ LogPipe *control;
2229+ LogWriterOptions *options;
2230+ GStaticMutex suppress_lock;
2231+ LogMessage *last_msg;
2232+ guint32 last_msg_count;
2233+ GString *line_buffer;
2234+
2235+ gint stats_level;
2236+ guint16 stats_source;
2237+ gchar *stats_id;
2238+ gchar *stats_instance;
2239+
2240+ struct iv_fd fd_watch;
2241+ struct iv_timer suspend_timer;
2242+ struct iv_task immed_io_task;
2243+ struct iv_event queue_filled;
2244+ MainLoopIOWorkerJob io_job;
2245+ struct iv_timer suppress_timer;
2246+ struct timespec suppress_timer_expires;
2247+ gboolean suppress_timer_updated;
2248+ gboolean work_result;
2249+ gint pollable_state;
2250+ LogProto *proto, *pending_proto;
2251+ gboolean watches_running:1, suspended:1, working:1, flush_waiting_for_timeout:1;
2252+ gboolean pending_proto_present;
2253+ GCond *pending_proto_cond;
2254+ GStaticMutex pending_proto_lock;
2255+};
2256+
2257+/**
2258+ * LogWriter behaviour
2259+ * ~~~~~~~~~~~~~~~~~~~
2260+ *
2261+ * LogWriter is a core element of syslog-ng sending messages out to some
2262+ * kind of destination represented by a UNIX fd. Outgoing messages are sent
2263+ * to the target asynchronously, first by placing them to a queue and then
2264+ * sending messages when poll() indicates that the fd is writable.
2265+ *
2266+ *
2267+ * Flow control
2268+ * ------------
2269+ * For a simple log writer without a disk buffer messages are placed on a
2270+ * GQueue and they are acknowledged when the send() system call returned
2271+ * success. This is more complex when disk buffering is used, in which case
2272+ * messages are put to the "disk buffer" first and acknowledged immediately.
2273+ * (this way the reader never stops when the disk buffer area is not yet
2274+ * full). When disk buffer reaches its limit, messages are added to the the
2275+ * usual GQueue and messages get acknowledged when they are moved to the
2276+ * disk buffer.
2277+ *
2278+ **/
2279+
2280+static gboolean log_writer_flush(LogWriter *self, LogWriterFlushMode flush_mode);
2281+static void log_writer_broken(LogWriter *self, gint notify_code);
2282+static void log_writer_start_watches(LogWriter *self);
2283+static void log_writer_stop_watches(LogWriter *self);
2284+static void log_writer_update_watches(LogWriter *self);
2285+static void log_writer_suspend(LogWriter *self);
2286+
2287+static void
2288+log_writer_work_perform(gpointer s)
2289+{
2290+ LogWriter *self = (LogWriter *) s;
2291+
2292+ g_assert((self->super.flags & PIF_INITIALIZED) != 0);
2293+ self->work_result = log_writer_flush(self, self->flush_waiting_for_timeout ? LW_FLUSH_BUFFER : LW_FLUSH_NORMAL);
2294+}
2295+
2296+static void
2297+log_writer_work_finished(gpointer s)
2298+{
2299+ LogWriter *self = (LogWriter *) s;
2300+
2301+ main_loop_assert_main_thread();
2302+ self->flush_waiting_for_timeout = FALSE;
2303+
2304+ if (self->pending_proto_present)
2305+ {
2306+ /* pending proto is only set in the main thread, so no need to
2307+ * lock it before coming here. After we're syncing with the
2308+ * log_writer_reopen() call, quite possibly coming from a
2309+ * non-main thread. */
2310+
2311+ g_static_mutex_lock(&self->pending_proto_lock);
2312+ if (self->proto)
2313+ log_proto_free(self->proto);
2314+
2315+ self->proto = self->pending_proto;
2316+ self->pending_proto = NULL;
2317+ self->pending_proto_present = FALSE;
2318+
2319+ g_cond_signal(self->pending_proto_cond);
2320+ g_static_mutex_unlock(&self->pending_proto_lock);
2321+ }
2322+
2323+ if (!self->work_result)
2324+ {
2325+ log_writer_broken(self, NC_WRITE_ERROR);
2326+ if (self->proto)
2327+ {
2328+ log_writer_suspend(self);
2329+ msg_notice("Suspending write operation because of an I/O error",
2330+ evt_tag_int("fd", log_proto_get_fd(self->proto)),
2331+ evt_tag_int("time_reopen", self->options->time_reopen),
2332+ NULL);
2333+ }
2334+ goto exit;
2335+ }
2336+
2337+ if ((self->super.flags & PIF_INITIALIZED) && self->proto)
2338+ {
2339+ /* reenable polling the source, but only if we're still initialized */
2340+ log_writer_start_watches(self);
2341+ }
2342+
2343+exit:
2344+ log_pipe_unref(&self->super);
2345+}
2346+
2347+static void
2348+log_writer_io_flush_output(gpointer s)
2349+{
2350+ LogWriter *self = (LogWriter *) s;
2351+
2352+ main_loop_assert_main_thread();
2353+
2354+ log_writer_stop_watches(self);
2355+ log_pipe_ref(&self->super);
2356+ if ((self->options->options & LWO_THREADED))
2357+ {
2358+ main_loop_io_worker_job_submit(&self->io_job);
2359+ }
2360+ else
2361+ {
2362+ log_writer_work_perform(s);
2363+ log_writer_work_finished(s);
2364+ }
2365+}
2366+
2367+static void
2368+log_writer_io_error(gpointer s)
2369+{
2370+ LogWriter *self = (LogWriter *) s;
2371+
2372+ if (self->fd_watch.handler_out == NULL && self->fd_watch.handler_in == NULL)
2373+ {
2374+ msg_debug("POLLERR occurred while idle",
2375+ evt_tag_int("fd", log_proto_get_fd(self->proto)),
2376+ NULL);
2377+ log_writer_broken(self, NC_WRITE_ERROR);
2378+ return;
2379+ }
2380+ else
2381+ {
2382+ /* in case we have an error state but we also asked for read/write
2383+ * polling, the error should be handled by the I/O callback. But we
2384+ * need not call that explicitly as ivykis does that for us. */
2385+ }
2386+ log_writer_update_watches(self);
2387+}
2388+
2389+static void
2390+log_writer_io_check_eof(gpointer s)
2391+{
2392+ LogWriter *self = (LogWriter *) s;
2393+
2394+ msg_error("EOF occurred while idle",
2395+ evt_tag_int("fd", log_proto_get_fd(self->proto)),
2396+ NULL);
2397+ log_writer_broken(self, NC_CLOSE);
2398+}
2399+
2400+static void
2401+log_writer_error_suspend_elapsed(gpointer s)
2402+{
2403+ LogWriter *self = (LogWriter *) s;
2404+
2405+ self->suspended = FALSE;
2406+ msg_notice("Error suspend timeout has elapsed, attempting to write again",
2407+ evt_tag_int("fd", log_proto_get_fd(self->proto)),
2408+ NULL);
2409+ log_writer_update_watches(self);
2410+}
2411+
2412+static void
2413+log_writer_update_fd_callbacks(LogWriter *self, GIOCondition cond)
2414+{
2415+ main_loop_assert_main_thread();
2416+ if (self->pollable_state > 0)
2417+ {
2418+ if (self->flags & LW_DETECT_EOF && (cond & G_IO_IN) == 0 && (cond & G_IO_OUT))
2419+ {
2420+ /* if output is enabled, and we're in DETECT_EOF mode, and input is
2421+ * not needed by the log protocol, install the eof check callback to
2422+ * destroy the connection if an EOF is received. */
2423+
2424+ iv_fd_set_handler_in(&self->fd_watch, log_writer_io_check_eof);
2425+ }
2426+ else if (cond & G_IO_IN)
2427+ {
2428+ /* in case the protocol requested G_IO_IN, it means that it needs to
2429+ * invoke read in the flush code, so just install the flush_output
2430+ * handler for input */
2431+
2432+ iv_fd_set_handler_in(&self->fd_watch, log_writer_io_flush_output);
2433+ }
2434+ else
2435+ {
2436+ /* otherwise we're not interested in input */
2437+ iv_fd_set_handler_in(&self->fd_watch, NULL);
2438+ }
2439+ if (cond & G_IO_OUT)
2440+ iv_fd_set_handler_out(&self->fd_watch, log_writer_io_flush_output);
2441+ else
2442+ iv_fd_set_handler_out(&self->fd_watch, NULL);
2443+
2444+ iv_fd_set_handler_err(&self->fd_watch, log_writer_io_error);
2445+ }
2446+ else
2447+ {
2448+ /* fd is not pollable, assume it is always writable */
2449+ if (cond & G_IO_OUT)
2450+ {
2451+ if (!iv_task_registered(&self->immed_io_task))
2452+ iv_task_register(&self->immed_io_task);
2453+ }
2454+ else if (iv_task_registered(&self->immed_io_task))
2455+ {
2456+ iv_task_unregister(&self->immed_io_task);
2457+ }
2458+ }
2459+}
2460+
2461+void
2462+log_writer_arm_suspend_timer(LogWriter *self, void (*handler)(void *), gint timeout_msec)
2463+{
2464+ if (iv_timer_registered(&self->suspend_timer))
2465+ iv_timer_unregister(&self->suspend_timer);
2466+ iv_validate_now();
2467+ self->suspend_timer.handler = handler;
2468+ self->suspend_timer.expires = iv_now;
2469+ timespec_add_msec(&self->suspend_timer.expires, timeout_msec);
2470+ iv_timer_register(&self->suspend_timer);
2471+}
2472+
2473+static void
2474+log_writer_queue_filled(gpointer s)
2475+{
2476+ LogWriter *self = (LogWriter *) s;
2477+
2478+ main_loop_assert_main_thread();
2479+
2480+ /*
2481+ * NOTE: This theory is somewhat questionable, e.g. I'm not 100% sure it
2482+ * is the right scenario, but the race was closed. So take this with a
2483+ * grain of salt.
2484+ *
2485+ * The queue_filled callback is running in the main thread. Because of the
2486+ * possible delay caused by iv_event_post() the callback might be
2487+ * delivered event after stop_watches() has been called.
2488+ *
2489+ * - log_writer_schedule_update_watches() is called by the reader
2490+ * thread, which calls iv_event_post()
2491+ * - the main thread calls stop_watches() in work_perform
2492+ * - the event is delivered in the main thread
2493+ *
2494+ * But since stop/start watches always run in the main thread and we do
2495+ * too, we can check if this is the case. A LogWriter without watches
2496+ * running is busy writing out data to the destination, e.g. a
2497+ * start_watches is to be expected once log_writer_work_finished() is run
2498+ * at the end of the deferred work, executed by the I/O threads.
2499+ */
2500+ if (self->watches_running)
2501+ log_writer_update_watches((LogWriter *) s);
2502+}
2503+
2504+/* NOTE: runs in the source thread */
2505+static void
2506+log_writer_schedule_update_watches(LogWriter *self)
2507+{
2508+ iv_event_post(&self->queue_filled);
2509+}
2510+
2511+static void
2512+log_writer_suspend(LogWriter *self)
2513+{
2514+ /* flush code indicates that we need to suspend our writing activities
2515+ * until time_reopen elapses */
2516+
2517+ log_writer_arm_suspend_timer(self, log_writer_error_suspend_elapsed, self->options->time_reopen * 1e3);
2518+ self->suspended = TRUE;
2519+}
2520+
2521+static void
2522+log_writer_update_watches(LogWriter *self)
2523+{
2524+ gint fd;
2525+ GIOCondition cond = 0;
2526+ gboolean partial_batch;
2527+ gint timeout_msec = 0;
2528+
2529+ main_loop_assert_main_thread();
2530+
2531+ /* NOTE: we either start the suspend_timer or enable the fd_watch. The two MUST not happen at the same time. */
2532+
2533+ if (log_proto_prepare(self->proto, &fd, &cond) ||
2534+ self->flush_waiting_for_timeout ||
2535+ log_queue_check_items(self->queue, self->options->flush_lines, &partial_batch, &timeout_msec,
2536+ (LogQueuePushNotifyFunc) log_writer_schedule_update_watches, self, NULL))
2537+ {
2538+ /* flush_lines number of element is already available and throttle would permit us to send. */
2539+ log_writer_update_fd_callbacks(self, cond);
2540+ }
2541+ else if (partial_batch || timeout_msec)
2542+ {
2543+ /* few elements are available, but less than flush_lines, we need to start a timer to initiate a flush */
2544+
2545+ log_writer_update_fd_callbacks(self, 0);
2546+ self->flush_waiting_for_timeout = TRUE;
2547+ log_writer_arm_suspend_timer(self, (void (*)(void *)) log_writer_update_watches, timeout_msec ? timeout_msec : self->options->flush_timeout);
2548+ }
2549+ else
2550+ {
2551+ /* no elements or no throttle space, wait for a wakeup by the queue
2552+ * when the required number of items are added. see the
2553+ * log_queue_check_items and its parallel_push argument above
2554+ */
2555+ log_writer_update_fd_callbacks(self, 0);
2556+ }
2557+}
2558+
2559+static gboolean
2560+is_file_regular(gint fd)
2561+{
2562+ struct stat st;
2563+
2564+ if (fstat(fd, &st) >= 0)
2565+ {
2566+ return S_ISREG(st.st_mode);
2567+ }
2568+
2569+ /* if stat fails, that's interesting, but we should probably poll
2570+ * it, hopefully that's less likely to cause spinning */
2571+
2572+ return FALSE;
2573+}
2574+
2575+static void
2576+log_writer_start_watches(LogWriter *self)
2577+{
2578+ gint fd;
2579+ GIOCondition cond;
2580+
2581+ if (!self->watches_running)
2582+ {
2583+ log_proto_prepare(self->proto, &fd, &cond);
2584+
2585+ if (self->pollable_state < 0)
2586+ {
2587+ if (is_file_regular(fd))
2588+ self->pollable_state = 0;
2589+ else
2590+ self->pollable_state = iv_fd_pollable(fd);
2591+ }
2592+
2593+ if (self->pollable_state)
2594+ {
2595+ self->fd_watch.fd = fd;
2596+ iv_fd_register(&self->fd_watch);
2597+ }
2598+
2599+ log_writer_update_watches(self);
2600+ self->watches_running = TRUE;
2601+ }
2602+}
2603+
2604+static void
2605+log_writer_stop_watches(LogWriter *self)
2606+{
2607+ if (self->watches_running)
2608+ {
2609+ if (iv_timer_registered(&self->suspend_timer))
2610+ iv_timer_unregister(&self->suspend_timer);
2611+ if (iv_fd_registered(&self->fd_watch))
2612+ iv_fd_unregister(&self->fd_watch);
2613+ if (iv_task_registered(&self->immed_io_task))
2614+ iv_task_unregister(&self->immed_io_task);
2615+
2616+ log_queue_reset_parallel_push(self->queue);
2617+
2618+ self->watches_running = FALSE;
2619+ }
2620+}
2621+
2622+/* function called using main_loop_call() in case the suppress timer needs
2623+ * to be updated */
2624+static void
2625+log_writer_perform_suppress_timer_update(LogWriter *self)
2626+{
2627+ main_loop_assert_main_thread();
2628+
2629+ if (iv_timer_registered(&self->suppress_timer))
2630+ iv_timer_unregister(&self->suppress_timer);
2631+ g_static_mutex_lock(&self->suppress_lock);
2632+ self->suppress_timer.expires = self->suppress_timer_expires;
2633+ self->suppress_timer_updated = TRUE;
2634+ g_static_mutex_unlock(&self->suppress_lock);
2635+ if (self->suppress_timer.expires.tv_sec > 0)
2636+ iv_timer_register(&self->suppress_timer);
2637+ log_pipe_unref(&self->super);
2638+}
2639+
2640+/*
2641+ * Update the suppress timer in a deferred manner, possibly batching the
2642+ * results of multiple updates to the suppress timer. This is necessary as
2643+ * suppress timer updates must run in the main thread, and updating it every
2644+ * time a new message comes in would cause enormous latency in the fast
2645+ * path. By collecting multiple updates
2646+ *
2647+ * msec == 0 means to turn off the suppress timer
2648+ * msec > 0 to enable the timer with the specified timeout
2649+ *
2650+ * NOTE: suppress_lock must be held.
2651+ */
2652+static void
2653+log_writer_update_suppress_timer(LogWriter *self, glong sec)
2654+{
2655+ gboolean invoke;
2656+ struct timespec next_expires;
2657+
2658+ iv_validate_now();
2659+
2660+ /* we deliberately use nsec == 0 in order to increase the likelyhood that
2661+ * we target the same second, in case only a fraction of a second has
2662+ * passed between two updates. */
2663+ if (sec)
2664+ {
2665+ next_expires.tv_nsec = 0;
2666+ next_expires.tv_sec = iv_now.tv_sec + sec;
2667+ }
2668+ else
2669+ {
2670+ next_expires.tv_sec = 0;
2671+ next_expires.tv_nsec = 0;
2672+ }
2673+ /* last update was finished, we need to invoke the updater again */
2674+ invoke = ((next_expires.tv_sec != self->suppress_timer_expires.tv_sec) || (next_expires.tv_nsec != self->suppress_timer_expires.tv_nsec)) && self->suppress_timer_updated;
2675+ self->suppress_timer_updated = FALSE;
2676+
2677+ if (invoke)
2678+ {
2679+ self->suppress_timer_expires = next_expires;
2680+ g_static_mutex_unlock(&self->suppress_lock);
2681+ log_pipe_ref(&self->super);
2682+ main_loop_call((void *(*)(void *)) log_writer_perform_suppress_timer_update, self, FALSE);
2683+ g_static_mutex_lock(&self->suppress_lock);
2684+ }
2685+
2686+}
2687+
2688+/*
2689+ * NOTE: suppress_lock must be held.
2690+ */
2691+static void
2692+log_writer_last_msg_release(LogWriter *self)
2693+{
2694+ log_writer_update_suppress_timer(self, 0);
2695+ if (self->last_msg)
2696+ log_msg_unref(self->last_msg);
2697+
2698+ self->last_msg = NULL;
2699+ self->last_msg_count = 0;
2700+}
2701+
2702+/*
2703+ * NOTE: suppress_lock must be held.
2704+ */
2705+static void
2706+log_writer_last_msg_flush(LogWriter *self)
2707+{
2708+ LogMessage *m;
2709+ LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
2710+ gchar hostname[256];
2711+ gchar buf[1024];
2712+ gssize len;
2713+ const gchar *p;
2714+
2715+ msg_debug("Suppress timer elapsed, emitting suppression summary",
2716+ NULL);
2717+
2718+ getlonghostname(hostname, sizeof(hostname));
2719+ m = log_msg_new_empty();
2720+ m->timestamps[LM_TS_STAMP] = m->timestamps[LM_TS_RECVD];
2721+ m->pri = self->last_msg->pri;
2722+ m->flags = LF_INTERNAL | LF_LOCAL;
2723+
2724+ p = log_msg_get_value(self->last_msg, LM_V_HOST, &len);
2725+ log_msg_set_value(m, LM_V_HOST, p, len);
2726+ p = log_msg_get_value(self->last_msg, LM_V_PROGRAM, &len);
2727+ log_msg_set_value(m, LM_V_PROGRAM, p, len);
2728+
2729+ len = g_snprintf(buf, sizeof(buf), "Last message '%.20s' repeated %d times, suppressed by syslog-ng on %s",
2730+ log_msg_get_value(self->last_msg, LM_V_MESSAGE, NULL),
2731+ self->last_msg_count,
2732+ hostname);
2733+ log_msg_set_value(m, LM_V_MESSAGE, buf, len);
2734+
2735+ path_options.ack_needed = FALSE;
2736+
2737+ log_queue_push_tail(self->queue, m, &path_options);
2738+ log_writer_last_msg_release(self);
2739+}
2740+
2741+
2742+/**
2743+ * Remember the last message for dup detection.
2744+ *
2745+ * NOTE: suppress_lock must be held.
2746+ **/
2747+static void
2748+log_writer_last_msg_record(LogWriter *self, LogMessage *lm)
2749+{
2750+ if (self->last_msg)
2751+ log_msg_unref(self->last_msg);
2752+
2753+ log_msg_ref(lm);
2754+ self->last_msg = lm;
2755+ self->last_msg_count = 0;
2756+}
2757+
2758+static gboolean
2759+log_writer_last_msg_timer(gpointer pt)
2760+{
2761+ LogWriter *self = (LogWriter *) pt;
2762+
2763+ main_loop_assert_main_thread();
2764+
2765+ g_static_mutex_lock(&self->suppress_lock);
2766+ log_writer_last_msg_flush(self);
2767+ g_static_mutex_unlock(&self->suppress_lock);
2768+
2769+ return FALSE;
2770+}
2771+
2772+/**
2773+ * log_writer_last_msg_check:
2774+ *
2775+ * This function is called to suppress duplicate messages from a given host.
2776+ *
2777+ * Returns TRUE to indicate that the message was consumed.
2778+ **/
2779+static gboolean
2780+log_writer_last_msg_check(LogWriter *self, LogMessage *lm, const LogPathOptions *path_options)
2781+{
2782+ g_static_mutex_lock(&self->suppress_lock);
2783+ if (self->last_msg)
2784+ {
2785+ if (self->last_msg->timestamps[LM_TS_RECVD].tv_sec >= lm->timestamps[LM_TS_RECVD].tv_sec - self->options->suppress &&
2786+ strcmp(log_msg_get_value(self->last_msg, LM_V_MESSAGE, NULL), log_msg_get_value(lm, LM_V_MESSAGE, NULL)) == 0 &&
2787+ strcmp(log_msg_get_value(self->last_msg, LM_V_HOST, NULL), log_msg_get_value(lm, LM_V_HOST, NULL)) == 0 &&
2788+ strcmp(log_msg_get_value(self->last_msg, LM_V_PROGRAM, NULL), log_msg_get_value(lm, LM_V_PROGRAM, NULL)) == 0 &&
2789+ strcmp(log_msg_get_value(self->last_msg, LM_V_PID, NULL), log_msg_get_value(lm, LM_V_PID, NULL)) == 0 &&
2790+ strcmp(log_msg_get_value(lm, LM_V_MESSAGE, NULL), "-- MARK --") != 0)
2791+ {
2792+ stats_counter_inc(self->suppressed_messages);
2793+ self->last_msg_count++;
2794+
2795+ if (self->last_msg_count == 1)
2796+ {
2797+ /* we only create the timer if this is the first suppressed message, otherwise it is already running. */
2798+
2799+ log_writer_update_suppress_timer(self, self->options->suppress);
2800+ }
2801+ g_static_mutex_unlock(&self->suppress_lock);
2802+
2803+ msg_debug("Suppressing duplicate message",
2804+ evt_tag_str("host", log_msg_get_value(lm, LM_V_HOST, NULL)),
2805+ evt_tag_str("msg", log_msg_get_value(lm, LM_V_MESSAGE, NULL)),
2806+ NULL);
2807+ log_msg_drop(lm, path_options);
2808+ return TRUE;
2809+ }
2810+
2811+ if (self->last_msg_count)
2812+ log_writer_last_msg_flush(self);
2813+ else
2814+ log_writer_last_msg_release(self);
2815+ }
2816+
2817+ log_writer_last_msg_record(self, lm);
2818+ g_static_mutex_unlock(&self->suppress_lock);
2819+ return FALSE;
2820+}
2821+
2822+/* NOTE: runs in the reader thread */
2823+static void
2824+log_writer_queue(LogPipe *s, LogMessage *lm, const LogPathOptions *path_options, gpointer user_data)
2825+{
2826+ LogWriter *self = (LogWriter *) s;
2827+ LogPathOptions local_options;
2828+
2829+ if (!path_options->flow_control_requested &&
2830+ (self->suspended || !(self->flags & LW_SOFT_FLOW_CONTROL)))
2831+ {
2832+ /* NOTE: this code ACKs the message back if there's a write error in
2833+ * order not to hang the client in case of a disk full */
2834+
2835+ path_options = log_msg_break_ack(lm, path_options, &local_options);
2836+ }
2837+ if (self->options->suppress > 0 && log_writer_last_msg_check(self, lm, path_options))
2838+ return;
2839+
2840+ stats_counter_inc(self->processed_messages);
2841+ log_queue_push_tail(self->queue, lm, path_options);
2842+}
2843+
2844+static void
2845+log_writer_append_value(GString *result, LogMessage *lm, NVHandle handle, gboolean use_nil, gboolean append_space)
2846+{
2847+ const gchar *value;
2848+ gssize value_len;
2849+
2850+ value = log_msg_get_value(lm, handle, &value_len);
2851+ if (use_nil && value_len == 0)
2852+ g_string_append_c(result, '-');
2853+ else
2854+ {
2855+ gchar *space;
2856+
2857+ space = strchr(value, ' ');
2858+
2859+ if (!space)
2860+ g_string_append_len(result, value, value_len);
2861+ else
2862+ g_string_append_len(result, value, space - value);
2863+ }
2864+ if (append_space)
2865+ g_string_append_c(result, ' ');
2866+}
2867+
2868+static void
2869+log_writer_do_padding(LogWriter *self, GString *result)
2870+{
2871+ if (!self->options->padding)
2872+ return;
2873+
2874+ if(G_UNLIKELY(self->options->padding < result->len))
2875+ {
2876+ msg_warning("Padding is too small to hold the full message",
2877+ evt_tag_int("padding", self->options->padding),
2878+ evt_tag_int("msg_size", result->len),
2879+ NULL);
2880+ g_string_set_size(result, self->options->padding);
2881+ return;
2882+ }
2883+ /* store the original length of the result */
2884+ gint len = result->len;
2885+ gint padd_bytes = self->options->padding - result->len;
2886+ /* set the size to the padded size, this will allocate the string */
2887+ g_string_set_size(result, self->options->padding);
2888+ memset(result->str + len - 1, '\0', padd_bytes);
2889+}
2890+
2891+void
2892+log_writer_format_log(LogWriter *self, LogMessage *lm, GString *result)
2893+{
2894+ LogTemplate *template = NULL;
2895+ LogStamp *stamp;
2896+ guint32 seq_num;
2897+ static NVHandle meta_seqid = 0;
2898+
2899+ if (!meta_seqid)
2900+ meta_seqid = log_msg_get_value_handle(".SDATA.meta.sequenceId");
2901+
2902+ if (lm->flags & LF_LOCAL)
2903+ {
2904+ seq_num = self->seq_num;
2905+ }
2906+ else
2907+ {
2908+ const gchar *seqid;
2909+ gssize seqid_length;
2910+
2911+ seqid = log_msg_get_value(lm, meta_seqid, &seqid_length);
2912+ APPEND_ZERO(seqid, seqid, seqid_length);
2913+ if (seqid[0])
2914+ seq_num = strtol(seqid, NULL, 10);
2915+ else
2916+ seq_num = 0;
2917+ }
2918+
2919+ /* no template was specified, use default */
2920+ stamp = &lm->timestamps[LM_TS_STAMP];
2921+
2922+ g_string_truncate(result, 0);
2923+
2924+ if ((self->flags & LW_SYSLOG_PROTOCOL) || (self->options->options & LWO_SYSLOG_PROTOCOL))
2925+ {
2926+ gint len;
2927+
2928+ /* we currently hard-wire version 1 */
2929+ g_string_append_c(result, '<');
2930+ format_uint32_padded(result, 0, 0, 10, lm->pri);
2931+ g_string_append_c(result, '>');
2932+ g_string_append_c(result, '1');
2933+ g_string_append_c(result, ' ');
2934+
2935+ log_stamp_append_format(stamp, result, TS_FMT_ISO,
2936+ time_zone_info_get_offset(self->options->template_options.time_zone_info[LTZ_SEND], stamp->tv_sec),
2937+ self->options->template_options.frac_digits);
2938+ g_string_append_c(result, ' ');
2939+
2940+ log_writer_append_value(result, lm, LM_V_HOST, TRUE, TRUE);
2941+ log_writer_append_value(result, lm, LM_V_PROGRAM, TRUE, TRUE);
2942+ log_writer_append_value(result, lm, LM_V_PID, TRUE, TRUE);
2943+ log_writer_append_value(result, lm, LM_V_MSGID, TRUE, TRUE);
2944+
2945+#if 0
2946+ if (lm->flags & LF_LOCAL)
2947+ {
2948+ gchar sequence_id[16];
2949+
2950+ g_snprintf(sequence_id, sizeof(sequence_id), "%d", seq_num);
2951+ log_msg_update_sdata(lm, "meta", "sequenceId", sequence_id);
2952+ }
2953+#endif
2954+ len = result->len;
2955+ log_msg_append_format_sdata(lm, result, seq_num);
2956+ if (len == result->len)
2957+ {
2958+ /* NOTE: sd_param format did not generate any output, take it as an empty SD string */
2959+ g_string_append_c(result, '-');
2960+ }
2961+
2962+ if (self->options->template)
2963+ {
2964+ g_string_append_c(result, ' ');
2965+ if (lm->flags & LF_UTF8)
2966+ g_string_append_len(result, "\xEF\xBB\xBF", 3);
2967+ log_template_append_format(self->options->template, lm,
2968+ &self->options->template_options,
2969+ LTZ_SEND,
2970+ seq_num, NULL,
2971+ result);
2972+ }
2973+ else
2974+ {
2975+ const gchar *p;
2976+ gssize len;
2977+
2978+ p = log_msg_get_value(lm, LM_V_MESSAGE, &len);
2979+ g_string_append_c(result, ' ');
2980+ if (len != 0)
2981+ {
2982+ if (lm->flags & LF_UTF8)
2983+ g_string_append_len(result, "\xEF\xBB\xBF", 3);
2984+
2985+ g_string_append_len(result, p, len);
2986+ }
2987+ }
2988+ g_string_append_c(result, '\n');
2989+ log_writer_do_padding(self, result);
2990+ }
2991+ else
2992+ {
2993+
2994+ if (self->options->template)
2995+ {
2996+ template = self->options->template;
2997+ }
2998+ else if (self->flags & LW_FORMAT_FILE)
2999+ {
3000+ template = self->options->file_template;
3001+ }
3002+ else if ((self->flags & LW_FORMAT_PROTO))
3003+ {
3004+ template = self->options->proto_template;
3005+ }
3006+
3007+ if (template)
3008+ {
3009+ log_template_format(template, lm,
3010+ &self->options->template_options,
3011+ LTZ_SEND,
3012+ seq_num, NULL,
3013+ result);
3014+
3015+ }
3016+ else
3017+ {
3018+ const gchar *p;
3019+ gssize len;
3020+
3021+ if (self->flags & LW_FORMAT_FILE)
3022+ {
3023+ log_stamp_format(stamp, result, self->options->template_options.ts_format,
3024+ time_zone_info_get_offset(self->options->template_options.time_zone_info[LTZ_SEND], stamp->tv_sec),
3025+ self->options->template_options.frac_digits);
3026+ }
3027+ else if (self->flags & LW_FORMAT_PROTO)
3028+ {
3029+ g_string_append_c(result, '<');
3030+ format_uint32_padded(result, 0, 0, 10, lm->pri);
3031+ g_string_append_c(result, '>');
3032+
3033+ /* always use BSD timestamp by default, the use can override this using a custom template */
3034+ log_stamp_append_format(stamp, result, TS_FMT_BSD,
3035+ time_zone_info_get_offset(self->options->template_options.time_zone_info[LTZ_SEND], stamp->tv_sec),
3036+ self->options->template_options.frac_digits);
3037+ }
3038+ g_string_append_c(result, ' ');
3039+
3040+ p = log_msg_get_value(lm, LM_V_HOST, &len);
3041+ g_string_append_len(result, p, len);
3042+ g_string_append_c(result, ' ');
3043+
3044+ if ((lm->flags & LF_LEGACY_MSGHDR))
3045+ {
3046+ p = log_msg_get_value(lm, LM_V_LEGACY_MSGHDR, &len);
3047+ g_string_append_len(result, p, len);
3048+ }
3049+ else
3050+ {
3051+ p = log_msg_get_value(lm, LM_V_PROGRAM, &len);
3052+ if (len > 0)
3053+ {
3054+ g_string_append_len(result, p, len);
3055+ p = log_msg_get_value(lm, LM_V_PID, &len);
3056+ if (len > 0)
3057+ {
3058+ g_string_append_c(result, '[');
3059+ g_string_append_len(result, p, len);
3060+ g_string_append_c(result, ']');
3061+ }
3062+ g_string_append_len(result, ": ", 2);
3063+ }
3064+ }
3065+ p = log_msg_get_value(lm, LM_V_MESSAGE, &len);
3066+ g_string_append_len(result, p, len);
3067+ g_string_append_c(result, '\n');
3068+ log_writer_do_padding(self, result);
3069+ }
3070+ }
3071+ if (self->options->options & LWO_NO_MULTI_LINE)
3072+ {
3073+ gchar *p;
3074+
3075+ p = result->str;
3076+ /* NOTE: the size is calculated to leave trailing new line */
3077+ while ((p = find_cr_or_lf(p, result->str + result->len - p - 1)))
3078+ {
3079+ *p = ' ';
3080+ p++;
3081+ }
3082+
3083+ }
3084+}
3085+
3086+static void
3087+log_writer_broken(LogWriter *self, gint notify_code)
3088+{
3089+ log_writer_stop_watches(self);
3090+ log_pipe_notify(self->control, &self->super, notify_code, self);
3091+}
3092+
3093+/*
3094+ * Write messages to the underlying file descriptor using the installed
3095+ * LogProto instance. This is called whenever the output is ready to accept
3096+ * further messages, and once during config deinitialization, in order to
3097+ * flush messages still in the queue, in the hope that most of them can be
3098+ * written out.
3099+ *
3100+ * In threaded mode, this function is invoked as part of the "output" task
3101+ * (in essence, this is the function that performs the output task).
3102+ *
3103+ * @flush_mode specifies how hard LogWriter is trying to send messages to
3104+ * the actual destination:
3105+ *
3106+ *
3107+ * LW_FLUSH_NORMAL - business as usual, flush when the buffer is full
3108+ * LW_FLUSH_BUFFER - flush the buffer immediately please
3109+ * LW_FLUSH_QUEUE - pull off any queued items, at maximum speed, even
3110+ * ignoring throttle, and flush the buffer too
3111+ *
3112+ */
3113+gboolean
3114+log_writer_flush(LogWriter *self, LogWriterFlushMode flush_mode)
3115+{
3116+ LogProto *proto = self->proto;
3117+ gint count = 0;
3118+ gboolean ignore_throttle = (flush_mode >= LW_FLUSH_QUEUE);
3119+
3120+ if (!proto)
3121+ return FALSE;
3122+
3123+ /* NOTE: in case we're reloading or exiting we flush all queued items as
3124+ * long as the destination can consume it. This is not going to be an
3125+ * infinite loop, since the reader will cease to produce new messages when
3126+ * main_loop_io_worker_job_quit() is set. */
3127+
3128+ while (!main_loop_io_worker_job_quit() || flush_mode >= LW_FLUSH_QUEUE)
3129+ {
3130+ LogMessage *lm;
3131+ LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
3132+ gboolean consumed = FALSE;
3133+
3134+ if (!log_queue_pop_head(self->queue, &lm, &path_options, FALSE, ignore_throttle))
3135+ {
3136+ /* no more items are available */
3137+ break;
3138+ }
3139+
3140+ log_msg_refcache_start_consumer(lm, &path_options);
3141+ msg_set_context(lm);
3142+
3143+ log_writer_format_log(self, lm, self->line_buffer);
3144+
3145+ if (self->line_buffer->len)
3146+ {
3147+ LogProtoStatus status;
3148+
3149+ status = log_proto_post(proto, (guchar *) self->line_buffer->str, self->line_buffer->len, &consumed);
3150+ if (status == LPS_ERROR)
3151+ {
3152+ if ((self->options->options & LWO_IGNORE_ERRORS) == 0)
3153+ {
3154+ msg_set_context(NULL);
3155+ log_msg_refcache_stop();
3156+ return FALSE;
3157+ }
3158+ else
3159+ {
3160+ if (!consumed)
3161+ g_free(self->line_buffer->str);
3162+ consumed = TRUE;
3163+ }
3164+ }
3165+ if (consumed)
3166+ {
3167+ self->line_buffer->str = g_malloc(self->line_buffer->allocated_len);
3168+ self->line_buffer->str[0] = 0;
3169+ self->line_buffer->len = 0;
3170+ }
3171+ }
3172+ if (consumed)
3173+ {
3174+ if (lm->flags & LF_LOCAL)
3175+ step_sequence_number(&self->seq_num);
3176+ log_msg_ack(lm, &path_options);
3177+ log_msg_unref(lm);
3178+ }
3179+ else
3180+ {
3181+ /* push back to the queue */
3182+ log_queue_push_head(self->queue, lm, &path_options);
3183+
3184+ msg_set_context(NULL);
3185+ log_msg_refcache_stop();
3186+ break;
3187+ }
3188+
3189+ msg_set_context(NULL);
3190+ log_msg_refcache_stop();
3191+ count++;
3192+ }
3193+
3194+ if (flush_mode >= LW_FLUSH_BUFFER || count == 0)
3195+ {
3196+ if (log_proto_flush(proto) == LPS_ERROR)
3197+ return FALSE;
3198+ }
3199+
3200+ return TRUE;
3201+}
3202+
3203+static void
3204+log_writer_init_watches(LogWriter *self)
3205+{
3206+ IV_FD_INIT(&self->fd_watch);
3207+ self->fd_watch.cookie = self;
3208+
3209+ IV_TASK_INIT(&self->immed_io_task);
3210+ self->immed_io_task.cookie = self;
3211+ self->immed_io_task.handler = log_writer_io_flush_output;
3212+
3213+ IV_TIMER_INIT(&self->suspend_timer);
3214+ self->suspend_timer.cookie = self;
3215+
3216+ IV_TIMER_INIT(&self->suppress_timer);
3217+ self->suppress_timer.cookie = self;
3218+ self->suppress_timer.handler = (void (*)(void *)) log_writer_last_msg_timer;
3219+
3220+ IV_EVENT_INIT(&self->queue_filled);
3221+ self->queue_filled.cookie = self;
3222+ self->queue_filled.handler = log_writer_queue_filled;
3223+
3224+ main_loop_io_worker_job_init(&self->io_job);
3225+ self->io_job.user_data = self;
3226+ self->io_job.work = (void (*)(void *)) log_writer_work_perform;
3227+ self->io_job.completion = (void (*)(void *)) log_writer_work_finished;
3228+}
3229+
3230+static gboolean
3231+log_writer_init(LogPipe *s)
3232+{
3233+ LogWriter *self = (LogWriter *) s;
3234+
3235+ g_assert(self->queue != NULL);
3236+ iv_event_register(&self->queue_filled);
3237+
3238+ if ((self->options->options & LWO_NO_STATS) == 0 && !self->dropped_messages)
3239+ {
3240+ stats_lock();
3241+ stats_register_counter(self->stats_level, self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_DROPPED, &self->dropped_messages);
3242+ if (self->options->suppress > 0)
3243+ stats_register_counter(self->stats_level, self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_SUPPRESSED, &self->suppressed_messages);
3244+ stats_register_counter(self->stats_level, self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_PROCESSED, &self->processed_messages);
3245+
3246+ stats_register_counter(self->stats_level, self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_STORED, &self->stored_messages);
3247+ stats_unlock();
3248+ }
3249+ self->suppress_timer_updated = TRUE;
3250+ log_queue_set_counters(self->queue, self->stored_messages, self->dropped_messages);
3251+ if (self->proto)
3252+ {
3253+ LogProto *proto;
3254+
3255+ proto = self->proto;
3256+ self->proto = NULL;
3257+ log_writer_reopen(&self->super, proto);
3258+ }
3259+ return TRUE;
3260+}
3261+
3262+static gboolean
3263+log_writer_deinit(LogPipe *s)
3264+{
3265+ LogWriter *self = (LogWriter *) s;
3266+
3267+ main_loop_assert_main_thread();
3268+
3269+ log_queue_reset_parallel_push(self->queue);
3270+ log_writer_flush(self, LW_FLUSH_QUEUE);
3271+ /* FIXME: by the time we arrive here, it must be guaranteed that no
3272+ * _queue() call is running in a different thread, otherwise we'd need
3273+ * some kind of locking. */
3274+
3275+ log_writer_stop_watches(self);
3276+ iv_event_unregister(&self->queue_filled);
3277+
3278+ if (iv_timer_registered(&self->suppress_timer))
3279+ iv_timer_unregister(&self->suppress_timer);
3280+
3281+ log_queue_set_counters(self->queue, NULL, NULL);
3282+
3283+ stats_lock();
3284+ stats_unregister_counter(self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_DROPPED, &self->dropped_messages);
3285+ stats_unregister_counter(self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_SUPPRESSED, &self->suppressed_messages);
3286+ stats_unregister_counter(self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_PROCESSED, &self->processed_messages);
3287+ stats_unregister_counter(self->stats_source | SCS_DESTINATION, self->stats_id, self->stats_instance, SC_TYPE_STORED, &self->stored_messages);
3288+ stats_unlock();
3289+
3290+ return TRUE;
3291+}
3292+
3293+static void
3294+log_writer_free(LogPipe *s)
3295+{
3296+ LogWriter *self = (LogWriter *) s;
3297+
3298+ if (self->proto)
3299+ log_proto_free(self->proto);
3300+
3301+ if (self->line_buffer)
3302+ g_string_free(self->line_buffer, TRUE);
3303+ if (self->queue)
3304+ log_queue_unref(self->queue);
3305+ if (self->last_msg)
3306+ log_msg_unref(self->last_msg);
3307+ g_free(self->stats_id);
3308+ g_free(self->stats_instance);
3309+ g_static_mutex_free(&self->suppress_lock);
3310+ g_static_mutex_free(&self->pending_proto_lock);
3311+ g_cond_free(self->pending_proto_cond);
3312+
3313+ log_pipe_free_method(s);
3314+}
3315+
3316+/* FIXME: this is inherently racy */
3317+gboolean
3318+log_writer_has_pending_writes(LogWriter *self)
3319+{
3320+ return log_queue_get_length(self->queue) > 0 || !self->watches_running;
3321+}
3322+
3323+gboolean
3324+log_writer_opened(LogWriter *self)
3325+{
3326+ return self->proto != NULL;
3327+}
3328+
3329+/* run in the main thread in reaction to a log_writer_reopen to change
3330+ * the destination LogProto instance. It needs to be ran in the main
3331+ * thread as it reregisters the watches associated with the main
3332+ * thread. */
3333+void
3334+log_writer_reopen_deferred(gpointer s)
3335+{
3336+ gpointer *args = (gpointer *) s;
3337+ LogWriter *self = args[0];
3338+ LogProto *proto = args[1];
3339+
3340+ init_sequence_number(&self->seq_num);
3341+
3342+ if (self->io_job.working)
3343+ {
3344+ /* NOTE: proto can be NULL */
3345+ self->pending_proto = proto;
3346+ self->pending_proto_present = TRUE;
3347+ return;
3348+ }
3349+
3350+ log_writer_stop_watches(self);
3351+
3352+ if (self->proto)
3353+ log_proto_free(self->proto);
3354+
3355+ self->proto = proto;
3356+
3357+ if (proto)
3358+ log_writer_start_watches(self);
3359+}
3360+
3361+/*
3362+ * This function can be called from any threads, from the main thread
3363+ * as well as I/O worker threads. It takes care about going to the
3364+ * main thread to actually switch LogProto under this writer.
3365+ *
3366+ * The writer may still be operating, (e.g. log_pipe_deinit/init is
3367+ * not needed).
3368+ *
3369+ * In case we're running in a non-main thread, then by the time this
3370+ * function returns, the reopen has finished. In case it is called
3371+ * from the main thread, this function may defer updating self->proto
3372+ * until the worker thread has finished. The reason for this
3373+ * difference is:
3374+ *
3375+ * - if LogWriter is busy, then updating the LogProto instance is
3376+ * deferred to log_writer_work_finished(), but that runs in the
3377+ * main thread.
3378+ *
3379+ * - normally, even this deferred update is waited for, but in case
3380+ * we're in the main thread, we can't block.
3381+ *
3382+ * This situation could probably be improved, maybe the synchonous
3383+ * return of log_writer_reopen() is not needed by call sites, but I
3384+ * was not sure, and right before release I didn't want to take the
3385+ * risky approach.
3386+ */
3387+void
3388+log_writer_reopen(LogPipe *s, LogProto *proto)
3389+{
3390+ LogWriter *self = (LogWriter *) s;
3391+ gpointer args[] = { s, proto };
3392+
3393+ main_loop_call((MainLoopTaskFunc) log_writer_reopen_deferred, args, TRUE);
3394+
3395+ if (!main_loop_is_main_thread())
3396+ {
3397+ g_static_mutex_lock(&self->pending_proto_lock);
3398+ while (self->pending_proto_present)
3399+ {
3400+ g_cond_wait(self->pending_proto_cond, g_static_mutex_get_mutex(&self->pending_proto_lock));
3401+ }
3402+ g_static_mutex_unlock(&self->pending_proto_lock);
3403+ }
3404+}
3405+
3406+void
3407+log_writer_set_options(LogWriter *self, LogPipe *control, LogWriterOptions *options, gint stats_level, gint stats_source, const gchar *stats_id, const gchar *stats_instance)
3408+{
3409+ self->control = control;
3410+ self->options = options;
3411+
3412+ self->stats_level = stats_level;
3413+ self->stats_source = stats_source;
3414+ self->stats_id = stats_id ? g_strdup(stats_id) : NULL;
3415+ self->stats_instance = stats_instance ? g_strdup(stats_instance) : NULL;
3416+
3417+}
3418+
3419+LogPipe *
3420+log_writer_new(guint32 flags)
3421+{
3422+ LogWriter *self = g_new0(LogWriter, 1);
3423+
3424+ log_pipe_init_instance(&self->super);
3425+ self->super.init = log_writer_init;
3426+ self->super.deinit = log_writer_deinit;
3427+ self->super.queue = log_writer_queue;
3428+ self->super.free_fn = log_writer_free;
3429+ self->flags = flags;
3430+ self->line_buffer = g_string_sized_new(128);
3431+ self->pollable_state = -1;
3432+ init_sequence_number(&self->seq_num);
3433+
3434+ log_writer_init_watches(self);
3435+ g_static_mutex_init(&self->suppress_lock);
3436+ g_static_mutex_init(&self->pending_proto_lock);
3437+ self->pending_proto_cond = g_cond_new();
3438+
3439+ return &self->super;
3440+}
3441+
3442+void
3443+log_writer_set_queue(LogPipe *s, LogQueue *queue)
3444+{
3445+ LogWriter *self = (LogWriter *)s;
3446+
3447+ if (self->queue)
3448+ log_queue_unref(self->queue);
3449+ self->queue = queue;
3450+}
3451+
3452+void
3453+log_writer_options_defaults(LogWriterOptions *options)
3454+{
3455+ options->template = NULL;
3456+ options->flush_lines = -1;
3457+ options->flush_timeout = -1;
3458+ log_template_options_defaults(&options->template_options);
3459+ options->time_reopen = -1;
3460+ options->suppress = -1;
3461+ options->padding = 0;
3462+}
3463+
3464+void
3465+log_writer_options_set_template_escape(LogWriterOptions *options, gboolean enable)
3466+{
3467+ if (options->template && options->template->def_inline)
3468+ {
3469+ log_template_set_escape(options->template, enable);
3470+ }
3471+ else
3472+ {
3473+ msg_error("Macro escaping can only be specified for inline templates", NULL);
3474+ }
3475+}
3476+
3477+
3478+/*
3479+ * NOTE: options_init and options_destroy are a bit weird, because their
3480+ * invocation is not completely symmetric:
3481+ *
3482+ * - init is called from driver init (e.g. affile_dd_init),
3483+ * - destroy is called from driver free method (e.g. affile_sd_free, NOT affile_dd_deinit)
3484+ *
3485+ * The reason:
3486+ * - when initializing the reloaded configuration fails for some reason,
3487+ * we have to fall back to the old configuration, thus we cannot dump
3488+ * the information stored in the Options structure.
3489+ *
3490+ * For the reasons above, init and destroy behave the following way:
3491+ *
3492+ * - init is idempotent, it can be called multiple times without leaking
3493+ * memory, and without loss of information
3494+ * - destroy is only called once, when the options are indeed to be destroyed
3495+ *
3496+ * As init allocates memory, it has to take care about freeing memory
3497+ * allocated by the previous init call (or it has to reuse those).
3498+ *
3499+ */
3500+void
3501+log_writer_options_init(LogWriterOptions *options, GlobalConfig *cfg, guint32 option_flags)
3502+{
3503+ LogTemplate *template;
3504+ gchar *time_zone[2];
3505+ TimeZoneInfo *time_zone_info[2];
3506+ gint i;
3507+
3508+ template = log_template_ref(options->template);
3509+
3510+ for (i = 0; i < LTZ_MAX; i++)
3511+ {
3512+ time_zone[i] = options->template_options.time_zone[i];
3513+ time_zone_info[i] = options->template_options.time_zone_info[i];
3514+ options->template_options.time_zone[i] = NULL;
3515+ options->template_options.time_zone_info[i] = NULL;
3516+ }
3517+
3518+ log_writer_options_destroy(options);
3519+ log_template_options_destroy(&options->template_options);
3520+
3521+ /* restroe the config */
3522+ options->template = template;
3523+ for (i = 0; i < LTZ_MAX; i++)
3524+ {
3525+ options->template_options.time_zone[i] = time_zone[i];
3526+ options->template_options.time_zone_info[i] = time_zone_info[i];
3527+ }
3528+ log_template_options_init(&options->template_options, cfg);
3529+ options->options |= option_flags;
3530+
3531+ if (options->flush_lines == -1)
3532+ options->flush_lines = cfg->flush_lines;
3533+ if (options->flush_timeout == -1)
3534+ options->flush_timeout = cfg->flush_timeout;
3535+ if (options->suppress == -1)
3536+ options->suppress = cfg->suppress;
3537+ if (options->time_reopen == -1)
3538+ options->time_reopen = cfg->time_reopen;
3539+ options->file_template = log_template_ref(cfg->file_template);
3540+ options->proto_template = log_template_ref(cfg->proto_template);
3541+ if (cfg->threaded)
3542+ options->options |= LWO_THREADED;
3543+}
3544+
3545+void
3546+log_writer_options_destroy(LogWriterOptions *options)
3547+{
3548+ log_template_options_destroy(&options->template_options);
3549+ log_template_unref(options->template);
3550+ log_template_unref(options->file_template);
3551+ log_template_unref(options->proto_template);
3552+}
3553+
3554+gint
3555+log_writer_options_lookup_flag(const gchar *flag)
3556+{
3557+ if (strcmp(flag, "syslog_protocol") == 0 || strcmp(flag, "syslog-protocol") == 0)
3558+ return LWO_SYSLOG_PROTOCOL;
3559+ if (strcmp(flag, "no-multi-line") == 0 || strcmp(flag, "no_multi_line") == 0)
3560+ return LWO_NO_MULTI_LINE;
3561+ if (strcmp(flag, "threaded") == 0)
3562+ return LWO_THREADED;
3563+ if (strcmp(flag, "ignore-errors") == 0 || strcmp(flag, "ignore_errors") == 0)
3564+ return LWO_IGNORE_ERRORS;
3565+ msg_error("Unknown dest writer flag", evt_tag_str("flag", flag), NULL);
3566+ return 0;
3567+}
3568
3569=== added file '.pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.h'
3570--- .pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.h 1970-01-01 00:00:00 +0000
3571+++ .pc/LogWriter-introduce-log_writer_get_queue-method.patch/lib/logwriter.h 2011-11-16 01:25:28 +0000
3572@@ -0,0 +1,89 @@
3573+/*
3574+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
3575+ * Copyright (c) 1998-2010 Balázs Scheidler
3576+ *
3577+ * This library is free software; you can redistribute it and/or
3578+ * modify it under the terms of the GNU Lesser General Public
3579+ * License as published by the Free Software Foundation; either
3580+ * version 2.1 of the License, or (at your option) any later version.
3581+ *
3582+ * This library is distributed in the hope that it will be useful,
3583+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3584+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3585+ * Lesser General Public License for more details.
3586+ *
3587+ * You should have received a copy of the GNU Lesser General Public
3588+ * License along with this library; if not, write to the Free Software
3589+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3590+ *
3591+ * As an additional exemption you are allowed to compile & link against the
3592+ * OpenSSL libraries as published by the OpenSSL project. See the file
3593+ * COPYING for details.
3594+ *
3595+ */
3596+
3597+#ifndef LOG_WRITER_H_INCLUDED
3598+#define LOG_WRITER_H_INCLUDED
3599+
3600+#include "logpipe.h"
3601+#include "templates.h"
3602+#include "logqueue.h"
3603+#include "logproto.h"
3604+#include "timeutils.h"
3605+
3606+/* writer constructor flags */
3607+#define LW_DETECT_EOF 0x0001
3608+#define LW_FORMAT_FILE 0x0002
3609+#define LW_FORMAT_PROTO 0x0004
3610+#define LW_SYSLOG_PROTOCOL 0x0008
3611+#define LW_SOFT_FLOW_CONTROL 0x0010
3612+
3613+/* writer options (set by the user) */
3614+#define LWO_SYSLOG_PROTOCOL 0x0001
3615+#define LWO_NO_MULTI_LINE 0x0002
3616+/* we don't want to have a dropped counter for this writer */
3617+#define LWO_NO_STATS 0x0004
3618+/* several writers use the same counter */
3619+#define LWO_SHARE_STATS 0x0008
3620+#define LWO_THREADED 0x0010
3621+#define LWO_IGNORE_ERRORS 0x0020
3622+
3623+typedef struct _LogWriterOptions
3624+{
3625+ /* bitmask of LWO_* */
3626+ guint32 options;
3627+
3628+ /* minimum number of entries to trigger a flush */
3629+ gint flush_lines;
3630+
3631+ /* flush anyway if this time was elapsed */
3632+ gint flush_timeout;
3633+ LogTemplate *template;
3634+ LogTemplate *file_template;
3635+ LogTemplate *proto_template;
3636+
3637+ gboolean fsync;
3638+ LogTemplateOptions template_options;
3639+
3640+ gint time_reopen;
3641+ gint suppress;
3642+ gint padding;
3643+} LogWriterOptions;
3644+
3645+typedef struct _LogWriter LogWriter;
3646+
3647+void log_writer_set_options(LogWriter *self, LogPipe *control, LogWriterOptions *options, gint stats_level, gint stats_source, const gchar *stats_id, const gchar *stats_instance);
3648+void log_writer_format_log(LogWriter *self, LogMessage *lm, GString *result);
3649+gboolean log_writer_has_pending_writes(LogWriter *self);
3650+gboolean log_writer_opened(LogWriter *self);
3651+void log_writer_reopen(LogPipe *s, LogProto *proto);
3652+LogPipe *log_writer_new(guint32 flags);
3653+void log_writer_set_queue(LogPipe *s, LogQueue *queue);
3654+
3655+void log_writer_options_set_template_escape(LogWriterOptions *options, gboolean enable);
3656+void log_writer_options_defaults(LogWriterOptions *options);
3657+void log_writer_options_init(LogWriterOptions *options, GlobalConfig *cfg, guint32 option_flags);
3658+void log_writer_options_destroy(LogWriterOptions *options);
3659+gint log_writer_options_lookup_flag(const gchar *flag);
3660+
3661+#endif
3662
3663=== added directory '.pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch'
3664=== added directory '.pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch/modules'
3665=== added directory '.pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch/modules/affile'
3666=== added file '.pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch/modules/affile/affile.c'
3667--- .pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch/modules/affile/affile.c 1970-01-01 00:00:00 +0000
3668+++ .pc/affile-release-per-writer-LogQueue-instances-during-runtime.patch/modules/affile/affile.c 2011-11-16 01:25:28 +0000
3669@@ -0,0 +1,1181 @@
3670+/*
3671+ * Copyright (c) 2002-2010 BalaBit IT Ltd, Budapest, Hungary
3672+ * Copyright (c) 1998-2010 Balázs Scheidler
3673+ *
3674+ * This program is free software; you can redistribute it and/or modify it
3675+ * under the terms of the GNU General Public License version 2 as published
3676+ * by the Free Software Foundation, or (at your option) any later version.
3677+ *
3678+ * This library is distributed in the hope that it will be useful,
3679+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3680+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3681+ * Lesser General Public License for more details.
3682+ *
3683+ * You should have received a copy of the GNU Lesser General Public
3684+ * License along with this library; if not, write to the Free Software
3685+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3686+ *
3687+ * As an additional exemption you are allowed to compile & link against the
3688+ * OpenSSL libraries as published by the OpenSSL project. See the file
3689+ * COPYING for details.
3690+ *
3691+ */
3692+#include "affile.h"
3693+#include "driver.h"
3694+#include "messages.h"
3695+#include "misc.h"
3696+#include "serialize.h"
3697+#include "gprocess.h"
3698+#include "stats.h"
3699+#include "mainloop.h"
3700+
3701+#include <sys/types.h>
3702+#include <sys/stat.h>
3703+#include <fcntl.h>
3704+#include <string.h>
3705+#include <unistd.h>
3706+#include <errno.h>
3707+#include <time.h>
3708+#include <stdlib.h>
3709+
3710+static gboolean
3711+affile_open_file(gchar *name, gint flags,
3712+ gint uid, gint gid, gint mode,
3713+ gint dir_uid, gint dir_gid, gint dir_mode,
3714+ gboolean create_dirs, gboolean privileged, gboolean is_pipe, gint *fd)
3715+{
3716+ cap_t saved_caps;
3717+ struct stat st;
3718+
3719+ if (strstr(name, "../") || strstr(name, "/.."))
3720+ {
3721+ msg_error("Spurious path, logfile not created",
3722+ evt_tag_str("path", name),
3723+ NULL);
3724+ return FALSE;
3725+ }
3726+
3727+ saved_caps = g_process_cap_save();
3728+ if (privileged)
3729+ {
3730+ g_process_cap_modify(CAP_DAC_READ_SEARCH, TRUE);
3731+ g_process_cap_modify(CAP_SYSLOG, TRUE);
3732+ }
3733+ else
3734+ {
3735+ g_process_cap_modify(CAP_DAC_OVERRIDE, TRUE);
3736+ }
3737+
3738+ if (create_dirs && !create_containing_directory(name, dir_uid, dir_gid, dir_mode))
3739+ {
3740+ g_process_cap_restore(saved_caps);
3741+ return FALSE;
3742+ }
3743+
3744+ *fd = -1;
3745+ if (stat(name, &st) >= 0)
3746+ {
3747+ if (is_pipe && !S_ISFIFO(st.st_mode))
3748+ {
3749+ msg_warning("WARNING: you are using the pipe driver, underlying file is not a FIFO, it should be used by file()",
3750+ evt_tag_str("filename", name),
3751+ NULL);
3752+ }
3753+ else if (!is_pipe && S_ISFIFO(st.st_mode))
3754+ {
3755+ msg_warning("WARNING: you are using the file driver, underlying file is a FIFO, it should be used by pipe()",
3756+ evt_tag_str("filename", name),
3757+ NULL);
3758+ }
3759+ }
3760+ *fd = open(name, flags, mode < 0 ? 0600 : mode);
3761+ if (is_pipe && *fd < 0 && errno == ENOENT)
3762+ {
3763+ if (mkfifo(name, 0666) >= 0)
3764+ *fd = open(name, flags, 0666);
3765+ }
3766+
3767+ if (*fd != -1)
3768+ {
3769+ g_fd_set_cloexec(*fd, TRUE);
3770+
3771+ g_process_cap_modify(CAP_CHOWN, TRUE);
3772+ g_process_cap_modify(CAP_FOWNER, TRUE);
3773+ set_permissions_fd(*fd, uid, gid, mode);
3774+ }
3775+ g_process_cap_restore(saved_caps);
3776+ msg_trace("affile_open_file",
3777+ evt_tag_str("path", name),
3778+ evt_tag_int("fd",*fd),
3779+ NULL);
3780+
3781+ return *fd != -1;
3782+}
3783+
3784+static gboolean
3785+affile_sd_open_file(AFFileSourceDriver *self, gchar *name, gint *fd)
3786+{
3787+ gint flags;
3788+
3789+ if (self->flags & AFFILE_PIPE)
3790+ flags = O_RDWR | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
3791+ else
3792+ flags = O_RDONLY | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
3793+
3794+ if (affile_open_file(name, flags, -1, -1, -1, 0, 0, 0, 0, !!(self->flags & AFFILE_PRIVILEGED), !!(self->flags & AFFILE_PIPE), fd))
3795+ return TRUE;
3796+ return FALSE;
3797+}
3798+
3799+static inline gchar *
3800+affile_sd_format_persist_name(AFFileSourceDriver *self)
3801+{
3802+ static gchar persist_name[1024];
3803+
3804+ g_snprintf(persist_name, sizeof(persist_name), "affile_sd_curpos(%s)", self->filename->str);
3805+ return persist_name;
3806+}
3807+
3808+static void
3809+affile_sd_recover_state(LogPipe *s, GlobalConfig *cfg, LogProto *proto)
3810+{
3811+ AFFileSourceDriver *self = (AFFileSourceDriver *) s;
3812+
3813+ if ((self->flags & AFFILE_PIPE) || self->reader_options.follow_freq <= 0)
3814+ return;
3815+
3816+ if (!log_proto_restart_with_state(proto, cfg->state, affile_sd_format_persist_name(self)))
3817+ {
3818+ msg_error("Error converting persistent state from on-disk format, losing file position information",
3819+ evt_tag_str("filename", self->filename->str),
3820+ NULL);
3821+ return;
3822+ }
3823+}
3824+
3825+static LogProto *
3826+affile_sd_construct_proto(AFFileSourceDriver *self, LogTransport *transport)
3827+{
3828+ guint flags;
3829+ LogProto *proto;
3830+ MsgFormatHandler *handler;
3831+
3832+ flags =
3833+ ((self->reader_options.follow_freq > 0)
3834+ ? LPBS_IGNORE_EOF | LPBS_POS_TRACKING
3835+ : LPBS_NOMREAD);
3836+
3837+ handler = self->reader_options.parse_options.format_handler;
3838+ if ((handler && handler->construct_proto))
3839+ proto = self->reader_options.parse_options.format_handler->construct_proto(&self->reader_options.parse_options, transport, flags);
3840+ else if (self->reader_options.padding)
3841+ proto = log_proto_record_server_new(transport, self->reader_options.padding, flags);
3842+ else
3843+ proto = log_proto_text_server_new(transport, self->reader_options.msg_size, flags);
3844+
3845+ return proto;
3846+}
3847+
3848+/* NOTE: runs in the main thread */
3849+static void
3850+affile_sd_notify(LogPipe *s, LogPipe *sender, gint notify_code, gpointer user_data)
3851+{
3852+ AFFileSourceDriver *self = (AFFileSourceDriver *) s;
3853+ GlobalConfig *cfg = log_pipe_get_config(s);
3854+ gint fd;
3855+
3856+ switch (notify_code)
3857+ {
3858+ case NC_FILE_MOVED:
3859+ {
3860+ msg_verbose("Follow-mode file source moved, tracking of the new file is started",
3861+ evt_tag_str("filename", self->filename->str),
3862+ NULL);
3863+
3864+ log_pipe_deinit(self->reader);
3865+ log_pipe_unref(self->reader);
3866+
3867+ if (affile_sd_open_file(self, self->filename->str, &fd))
3868+ {
3869+ LogTransport *transport;
3870+ LogProto *proto;
3871+
3872+ transport = log_transport_plain_new(fd, 0);
3873+ transport->timeout = 10;
3874+
3875+ proto = affile_sd_construct_proto(self, transport);
3876+
3877+ self->reader = log_reader_new(proto);
3878+
3879+ log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.super.id, self->filename->str);
3880+ log_reader_set_follow_filename(self->reader, self->filename->str);
3881+ log_reader_set_immediate_check(self->reader);
3882+
3883+ log_pipe_append(self->reader, s);
3884+ if (!log_pipe_init(self->reader, cfg))
3885+ {
3886+ msg_error("Error initializing log_reader, closing fd",
3887+ evt_tag_int("fd", fd),
3888+ NULL);
3889+ log_pipe_unref(self->reader);
3890+ self->reader = NULL;
3891+ close(fd);
3892+ }
3893+ affile_sd_recover_state(s, cfg, proto);
3894+ }
3895+ else
3896+ {
3897+ self->reader = NULL;
3898+ }
3899+ break;
3900+ }
3901+ default:
3902+ break;
3903+ }
3904+}
3905+
3906+static void
3907+affile_sd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options, gpointer user_data)
3908+{
3909+ AFFileSourceDriver *self = (AFFileSourceDriver *) s;
3910+ static NVHandle filename_handle = 0;
3911+
3912+ if (!filename_handle)
3913+ filename_handle = log_msg_get_value_handle("FILE_NAME");
3914+
3915+ log_msg_set_value(msg, filename_handle, self->filename->str, self->filename->len);
3916+
3917+ log_pipe_forward_msg(s, msg, path_options);
3918+}
3919+
3920+static gboolean
3921+affile_sd_init(LogPipe *s)
3922+{
3923+ AFFileSourceDriver *self = (AFFileSourceDriver *) s;
3924+ GlobalConfig *cfg = log_pipe_get_config(s);
3925+ gint fd;
3926+ gboolean file_opened, open_deferred = FALSE;
3927+
3928+ if (!log_src_driver_init_method(s))
3929+ return FALSE;
3930+
3931+ log_reader_options_init(&self->reader_options, cfg, self->super.super.group);
3932+
3933+ file_opened = affile_sd_open_file(self, self->filename->str, &fd);
3934+ if (!file_opened && self->reader_options.follow_freq > 0)
3935+ {
3936+ msg_info("Follow-mode file source not found, deferring open",
3937+ evt_tag_str("filename", self->filename->str),
3938+ NULL);
3939+ open_deferred = TRUE;
3940+ fd = -1;
3941+ }
3942+
3943+ if (file_opened || open_deferred)
3944+ {
3945+ LogTransport *transport;
3946+ LogProto *proto;
3947+
3948+ transport = log_transport_plain_new(fd, 0);
3949+ transport->timeout = 10;
3950+
3951+ proto = affile_sd_construct_proto(self, transport);
3952+ /* FIXME: we shouldn't use reader_options to store log protocol parameters */
3953+ self->reader = log_reader_new(proto);
3954+
3955+ log_reader_set_options(self->reader, s, &self->reader_options, 1, SCS_FILE, self->super.super.id, self->filename->str);
3956+ log_reader_set_follow_filename(self->reader, self->filename->str);
3957+
3958+ /* NOTE: if the file could not be opened, we ignore the last
3959+ * remembered file position, if the file is created in the future
3960+ * we're going to read from the start. */
3961+
3962+ log_pipe_append(self->reader, s);
3963+
3964+ if (!log_pipe_init(self->reader, NULL))
3965+ {
3966+ msg_error("Error initializing log_reader, closing fd",
3967+ evt_tag_int("fd", fd),
3968+ NULL);
3969+ log_pipe_unref(self->reader);
3970+ self->reader = NULL;
3971+ close(fd);
3972+ return FALSE;
3973+ }
3974+ affile_sd_recover_state(s, cfg, proto);
3975+ }
3976+ else
3977+ {
3978+ msg_error("Error opening file for reading",
3979+ evt_tag_str("filename", self->filename->str),
3980+ evt_tag_errno(EVT_TAG_OSERROR, errno),
3981+ NULL);
3982+ return self->super.super.optional;
3983+ }
3984+ return TRUE;
3985+
3986+}
3987+
3988+static gboolean
3989+affile_sd_deinit(LogPipe *s)
3990+{
3991+ AFFileSourceDriver *self = (AFFileSourceDriver *) s;
3992+
3993+ if (self->reader)
3994+ {
3995+ log_pipe_deinit(self->reader);
3996+ log_pipe_unref(self->reader);
3997+ self->reader = NULL;
3998+ }
3999+
4000+ if (!log_src_driver_deinit_method(s))
4001+ return FALSE;
4002+
4003+ return TRUE;
4004+}
4005+
4006+static void
4007+affile_sd_free(LogPipe *s)
4008+{
4009+ AFFileSourceDriver *self = (AFFileSourceDriver *) s;
4010+
4011+ g_string_free(self->filename, TRUE);
4012+ g_assert(!self->reader);
4013+
4014+ log_reader_options_destroy(&self->reader_options);
4015+
4016+ log_src_driver_free(s);
4017+}
4018+
4019+LogDriver *
4020+affile_sd_new(gchar *filename, guint32 flags)
4021+{
4022+ AFFileSourceDriver *self = g_new0(AFFileSourceDriver, 1);
4023+
4024+ log_src_driver_init_instance(&self->super);
4025+ self->filename = g_string_new(filename);
4026+ self->flags = flags;
4027+ self->super.super.super.init = affile_sd_init;
4028+ self->super.super.super.queue = affile_sd_queue;
4029+ self->super.super.super.deinit = affile_sd_deinit;
4030+ self->super.super.super.notify = affile_sd_notify;
4031+ self->super.super.super.free_fn = affile_sd_free;
4032+ log_reader_options_defaults(&self->reader_options);
4033+ self->reader_options.parse_options.flags |= LP_LOCAL;
4034+
4035+ if ((self->flags & AFFILE_PIPE))
4036+ {
4037+ static gboolean warned = FALSE;
4038+
4039+ if (configuration && configuration->version < 0x0302)
4040+ {
4041+ if (!warned)
4042+ {
4043+ msg_warning("WARNING: the expected message format is being changed for pipe() to improve "
4044+ "syslogd compatibity with syslog-ng 3.2. If you are using custom "
4045+ "applications which bypass the syslog() API, you might "
4046+ "need the 'expect-hostname' flag to get the old behaviour back", NULL);
4047+ warned = TRUE;
4048+ }
4049+ }
4050+ else
4051+ {
4052+ self->reader_options.parse_options.flags &= ~LP_EXPECT_HOSTNAME;
4053+ }
4054+ }
4055+
4056+ if (configuration && configuration->version < 0x0300)
4057+ {
4058+ static gboolean warned = FALSE;
4059+
4060+ if (!warned)
4061+ {
4062+ msg_warning("WARNING: file source: default value of follow_freq in file sources is changing in 3.0 to '1' for all files except /proc/kmsg",
4063+ NULL);
4064+ warned = TRUE;
4065+ }
4066+ }
4067+ else
4068+ {
4069+ if ((self->flags & AFFILE_PIPE) == 0)
4070+ {
4071+ if (0 ||
4072+#if __linux__
4073+ (strcmp(filename, "/proc/kmsg") == 0) ||
4074+#elif __FreeBSD__
4075+ (strcmp(filename, "/dev/klog") == 0) ||
4076+#endif
4077+ 0)
4078+ {
4079+ self->reader_options.follow_freq = 0;
4080+ }
4081+ else
4082+ {
4083+ self->reader_options.follow_freq = 1000;
4084+ }
4085+ }
4086+ }
4087+#if __linux__
4088+ if (strcmp(filename, "/proc/kmsg") == 0)
4089+ {
4090+ self->flags |= AFFILE_PRIVILEGED;
4091+ }
4092+#endif
4093+ return &self->super.super;
4094+}
4095+
4096+/*
4097+ * Threading notes:
4098+ *
4099+ * Apart from standard initialization/deinitialization (normally performed
4100+ * by the main thread when syslog-ng starts up) the following processes are
4101+ * performed in various threads.
4102+ *
4103+ * - queue runs in the thread of the source thread that generated the message
4104+ * - if the message is to be written to a not-yet-opened file, a new gets
4105+ * opened and stored in the writer_hash hashtable (initiated from queue,
4106+ * but performed in the main thread, but more on that later)
4107+ * - currently opened destination files are checked regularly and closed
4108+ * if they are idle for a given amount of time (time_reap) (this is done
4109+ * in the main thread)
4110+ *
4111+ * Some of these operations have to be performed in the main thread, others
4112+ * are done in the queue call.
4113+ *
4114+ * References
4115+ * ==========
4116+ *
4117+ * The AFFileDestDriver instance is registered into the current
4118+ * configuration, thus its presence is always given, it cannot go away while
4119+ * syslog-ng is running.
4120+ *
4121+ * AFFileDestWriter instances are created dynamically when a new file is
4122+ * opened. A reference is stored in the writer_hash hashtable. This is then:
4123+ * - looked up in _queue() (in the source thread)
4124+ * - cleaned up in reap callback (in the main thread)
4125+ *
4126+ * writer_hash is locked (currently a simple mutex) using
4127+ * AFFileDestDriver->lock. The "queue" method cannot hold the lock while
4128+ * forwarding it to the next pipe, thus a reference is taken under the
4129+ * protection of the lock, keeping a the next pipe alive, even if that would
4130+ * go away in a parallel reaper process.
4131+ */
4132+
4133+struct _AFFileDestWriter
4134+{
4135+ LogPipe super;
4136+ GStaticMutex lock;
4137+ AFFileDestDriver *owner;
4138+ gchar *filename;
4139+ LogPipe *writer;
4140+ time_t last_msg_stamp;
4141+ time_t last_open_stamp;
4142+ time_t time_reopen;
4143+ struct iv_timer reap_timer;
4144+ gboolean reopen_pending, queue_pending;
4145+};
4146+
4147+static void affile_dd_reap_writer(AFFileDestDriver *self, AFFileDestWriter *dw);
4148+
4149+static void
4150+affile_dw_arm_reaper(AFFileDestWriter *self)
4151+{
4152+ /* not yet reaped, set up the next callback */
4153+ iv_validate_now();
4154+ self->reap_timer.expires = iv_now;
4155+ timespec_add_msec(&self->reap_timer.expires, self->owner->time_reap * 1000 / 2);
4156+ iv_timer_register(&self->reap_timer);
4157+}
4158+
4159+static void
4160+affile_dw_reap(gpointer s)
4161+{
4162+ AFFileDestWriter *self = (AFFileDestWriter *) s;
4163+
4164+ main_loop_assert_main_thread();
4165+
4166+ g_static_mutex_lock(&self->lock);
4167+ if (!log_writer_has_pending_writes((LogWriter *) self->writer) &&
4168+ !self->queue_pending &&
4169+ (cached_g_current_time_sec() - self->last_msg_stamp) >= self->owner->time_reap)
4170+ {
4171+ g_static_mutex_unlock(&self->lock);
4172+ msg_verbose("Destination timed out, reaping",
4173+ evt_tag_str("template", self->owner->filename_template->template),
4174+ evt_tag_str("filename", self->filename),
4175+ NULL);
4176+ affile_dd_reap_writer(self->owner, self);
4177+ }
4178+ else
4179+ {
4180+ g_static_mutex_unlock(&self->lock);
4181+ affile_dw_arm_reaper(self);
4182+ }
4183+}
4184+
4185+static gboolean
4186+affile_dw_reopen(AFFileDestWriter *self)
4187+{
4188+ int fd, flags;
4189+ struct stat st;
4190+
4191+ self->last_open_stamp = self->last_msg_stamp;
4192+ if (self->owner->overwrite_if_older > 0 &&
4193+ stat(self->filename, &st) == 0 &&
4194+ st.st_mtime < time(NULL) - self->owner->overwrite_if_older)
4195+ {
4196+ msg_info("Destination file is older than overwrite_if_older(), overwriting",
4197+ evt_tag_str("filename", self->filename),
4198+ evt_tag_int("overwrite_if_older", self->owner->overwrite_if_older),
4199+ NULL);
4200+ unlink(self->filename);
4201+ }
4202+
4203+ if (self->owner->flags & AFFILE_PIPE)
4204+ flags = O_RDWR | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
4205+ else
4206+ flags = O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK | O_LARGEFILE;
4207+
4208+
4209+ if (affile_open_file(self->filename, flags,
4210+ self->owner->file_uid, self->owner->file_gid, self->owner->file_perm,
4211+ self->owner->dir_uid, self->owner->dir_gid, self->owner->dir_perm,
4212+ !!(self->owner->flags & AFFILE_CREATE_DIRS), FALSE, !!(self->owner->flags & AFFILE_PIPE), &fd))
4213+ {
4214+ guint write_flags;
4215+
4216+ write_flags =
4217+ ((self->owner->flags & AFFILE_PIPE) ? LTF_PIPE : LTF_APPEND) |
4218+ ((self->owner->flags & AFFILE_FSYNC) ? LTF_FSYNC : 0);
4219+ log_writer_reopen(self->writer,
4220+ self->owner->flags & AFFILE_PIPE
4221+ ? log_proto_text_client_new(log_transport_plain_new(fd, write_flags))
4222+ : log_proto_file_writer_new(log_transport_plain_new(fd, write_flags), self->owner->writer_options.flush_lines));
4223+
4224+ main_loop_call((void * (*)(void *)) affile_dw_arm_reaper, self, TRUE);
4225+ }
4226+ else
4227+ {
4228+ msg_error("Error opening file for writing",
4229+ evt_tag_str("filename", self->filename),
4230+ evt_tag_errno(EVT_TAG_OSERROR, errno),
4231+ NULL);
4232+ return self->owner->super.super.optional;
4233+ }
4234+ return TRUE;
4235+}
4236+
4237+static gboolean
4238+affile_dw_init(LogPipe *s)
4239+{
4240+ AFFileDestWriter *self = (AFFileDestWriter *) s;
4241+ GlobalConfig *cfg = log_pipe_get_config(s);
4242+
4243+ if (cfg)
4244+ self->time_reopen = cfg->time_reopen;
4245+
4246+ msg_verbose("Initializing destination file writer",
4247+ evt_tag_str("template", self->owner->filename_template->template),
4248+ evt_tag_str("filename", self->filename),
4249+ NULL);
4250+
4251+ if (!self->writer)
4252+ {
4253+ guint32 flags;
4254+
4255+ flags = LW_FORMAT_FILE |
4256+ ((self->owner->flags & AFFILE_PIPE) ? 0 : LW_SOFT_FLOW_CONTROL);
4257+
4258+ self->writer = log_writer_new(flags);
4259+ }
4260+ log_writer_set_options((LogWriter *) self->writer, s, &self->owner->writer_options, 1,
4261+ self->owner->flags & AFFILE_PIPE ? SCS_PIPE : SCS_FILE,
4262+ self->owner->super.super.id, self->filename);
4263+ log_writer_set_queue(self->writer, log_dest_driver_acquire_queue(&self->owner->super, NULL));
4264+
4265+ if (!log_pipe_init(self->writer, NULL))
4266+ {
4267+ msg_error("Error initializing log writer", NULL);
4268+ log_pipe_unref(self->writer);
4269+ self->writer = NULL;
4270+ return FALSE;
4271+ }
4272+ log_pipe_append(&self->super, self->writer);
4273+
4274+ return affile_dw_reopen(self);
4275+}
4276+
4277+static gboolean
4278+affile_dw_deinit(LogPipe *s)
4279+{
4280+ AFFileDestWriter *self = (AFFileDestWriter *) s;
4281+
4282+ main_loop_assert_main_thread();
4283+ if (self->writer)
4284+ {
4285+ log_pipe_deinit(self->writer);
4286+ }
4287+ if (iv_timer_registered(&self->reap_timer))
4288+ iv_timer_unregister(&self->reap_timer);
4289+ return TRUE;
4290+}
4291+
4292+/*
4293+ * NOTE: the caller (e.g. AFFileDestDriver) holds a reference to @self, thus
4294+ * @self may _never_ be freed, even if the reaper timer is elapsed in the
4295+ * main thread.
4296+ */
4297+static void
4298+affile_dw_queue(LogPipe *s, LogMessage *lm, const LogPathOptions *path_options, gpointer user_data)
4299+{
4300+ AFFileDestWriter *self = (AFFileDestWriter *) s;
4301+
4302+ g_static_mutex_lock(&self->lock);
4303+ self->last_msg_stamp = cached_g_current_time_sec();
4304+ if (self->last_open_stamp == 0)
4305+ self->last_open_stamp = self->last_msg_stamp;
4306+
4307+ if (!log_writer_opened((LogWriter *) self->writer) &&
4308+ !self->reopen_pending &&
4309+ (self->last_open_stamp < self->last_msg_stamp - self->time_reopen))
4310+ {
4311+ self->reopen_pending = TRUE;
4312+ /* if the file couldn't be opened, try it again every time_reopen seconds */
4313+ g_static_mutex_unlock(&self->lock);
4314+ affile_dw_reopen(self);
4315+ g_static_mutex_lock(&self->lock);
4316+ self->reopen_pending = FALSE;
4317+ }
4318+ g_static_mutex_unlock(&self->lock);
4319+
4320+ log_pipe_forward_msg(&self->super, lm, path_options);
4321+}
4322+
4323+static void
4324+affile_dw_set_owner(AFFileDestWriter *self, AFFileDestDriver *owner)
4325+{
4326+ if (self->owner)
4327+ log_pipe_unref(&self->owner->super.super.super);
4328+ log_pipe_ref(&owner->super.super.super);
4329+ self->owner = owner;
4330+ if (self->writer)
4331+ log_writer_set_options((LogWriter *) self->writer, &self->super, &owner->writer_options, 1, SCS_FILE, self->owner->super.super.id, self->filename);
4332+
4333+}
4334+
4335+static void
4336+affile_dw_free(LogPipe *s)
4337+{
4338+ AFFileDestWriter *self = (AFFileDestWriter *) s;
4339+
4340+ log_pipe_unref(self->writer);
4341+ self->writer = NULL;
4342+ g_free(self->filename);
4343+ log_pipe_unref(&self->owner->super.super.super);
4344+ log_pipe_free_method(s);
4345+}
4346+
4347+static AFFileDestWriter *
4348+affile_dw_new(AFFileDestDriver *owner, const gchar *filename)
4349+{
4350+ AFFileDestWriter *self = g_new0(AFFileDestWriter, 1);
4351+
4352+ log_pipe_init_instance(&self->super);
4353+
4354+ self->super.init = affile_dw_init;
4355+ self->super.deinit = affile_dw_deinit;
4356+ self->super.free_fn = affile_dw_free;
4357+ self->super.queue = affile_dw_queue;
4358+ log_pipe_ref(&owner->super.super.super);
4359+ self->owner = owner;
4360+ self->time_reopen = 60;
4361+
4362+ IV_TIMER_INIT(&self->reap_timer);
4363+ self->reap_timer.cookie = self;
4364+ self->reap_timer.handler = affile_dw_reap;
4365+
4366+ /* we have to take care about freeing filename later.
4367+ This avoids a move of the filename. */
4368+ self->filename = g_strdup(filename);
4369+ g_static_mutex_init(&self->lock);
4370+ return self;
4371+}
4372+
4373+void
4374+affile_dd_set_file_uid(LogDriver *s, const gchar *file_uid)
4375+{
4376+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4377+
4378+ self->file_uid = 0;
4379+ if (!resolve_user(file_uid, &self->file_uid))
4380+ {
4381+ msg_error("Error resolving user",
4382+ evt_tag_str("user", file_uid),
4383+ NULL);
4384+ }
4385+}
4386+
4387+void
4388+affile_dd_set_file_gid(LogDriver *s, const gchar *file_gid)
4389+{
4390+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4391+
4392+ self->file_gid = 0;
4393+ if (!resolve_group(file_gid, &self->file_gid))
4394+ {
4395+ msg_error("Error resolving group",
4396+ evt_tag_str("group", file_gid),
4397+ NULL);
4398+ }
4399+}
4400+
4401+void
4402+affile_dd_set_file_perm(LogDriver *s, gint file_perm)
4403+{
4404+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4405+
4406+ self->file_perm = file_perm;
4407+}
4408+
4409+void
4410+affile_dd_set_dir_uid(LogDriver *s, const gchar *dir_uid)
4411+{
4412+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4413+
4414+ self->dir_uid = 0;
4415+ if (!resolve_user(dir_uid, &self->dir_uid))
4416+ {
4417+ msg_error("Error resolving user",
4418+ evt_tag_str("user", dir_uid),
4419+ NULL);
4420+ }
4421+}
4422+
4423+void
4424+affile_dd_set_dir_gid(LogDriver *s, const gchar *dir_gid)
4425+{
4426+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4427+
4428+ self->dir_gid = 0;
4429+ if (!resolve_group(dir_gid, &self->dir_gid))
4430+ {
4431+ msg_error("Error resolving group",
4432+ evt_tag_str("group", dir_gid),
4433+ NULL);
4434+ }
4435+}
4436+
4437+void
4438+affile_dd_set_dir_perm(LogDriver *s, gint dir_perm)
4439+{
4440+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4441+
4442+ self->dir_perm = dir_perm;
4443+}
4444+
4445+void
4446+affile_dd_set_create_dirs(LogDriver *s, gboolean create_dirs)
4447+{
4448+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4449+
4450+ if (create_dirs)
4451+ self->flags |= AFFILE_CREATE_DIRS;
4452+ else
4453+ self->flags &= ~AFFILE_CREATE_DIRS;
4454+}
4455+
4456+void
4457+affile_dd_set_overwrite_if_older(LogDriver *s, gint overwrite_if_older)
4458+{
4459+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4460+
4461+ self->overwrite_if_older = overwrite_if_older;
4462+}
4463+
4464+void
4465+affile_dd_set_fsync(LogDriver *s, gboolean fsync)
4466+{
4467+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4468+ if (fsync)
4469+ self->flags |= AFFILE_FSYNC;
4470+ else
4471+ self->flags &= ~AFFILE_FSYNC;
4472+}
4473+
4474+void
4475+affile_dd_set_local_time_zone(LogDriver *s, const gchar *local_time_zone)
4476+{
4477+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4478+
4479+ self->local_time_zone = g_strdup(local_time_zone);
4480+}
4481+
4482+static inline gchar *
4483+affile_dd_format_persist_name(AFFileDestDriver *self)
4484+{
4485+ static gchar persist_name[1024];
4486+
4487+ g_snprintf(persist_name, sizeof(persist_name), "affile_dd_writers(%s)", self->filename_template->template);
4488+ return persist_name;
4489+}
4490+
4491+static void
4492+affile_dd_reap_writer(AFFileDestDriver *self, AFFileDestWriter *dw)
4493+{
4494+ main_loop_assert_main_thread();
4495+
4496+ if ((self->flags & AFFILE_NO_EXPAND) == 0)
4497+ {
4498+ g_static_mutex_lock(&self->lock);
4499+ /* remove from hash table */
4500+ g_hash_table_remove(self->writer_hash, dw->filename);
4501+ g_static_mutex_unlock(&self->lock);
4502+ }
4503+ else
4504+ {
4505+ g_static_mutex_lock(&self->lock);
4506+ g_assert(dw == self->single_writer);
4507+ self->single_writer = NULL;
4508+ g_static_mutex_unlock(&self->lock);
4509+ }
4510+
4511+ log_pipe_deinit(&dw->super);
4512+ log_pipe_unref(&dw->super);
4513+}
4514+
4515+
4516+/**
4517+ * affile_dd_reuse_writer:
4518+ *
4519+ * This function is called as a g_hash_table_foreach() callback to set the
4520+ * owner of each writer, previously connected to an AFileDestDriver instance
4521+ * in an earlier configuration. This way AFFileDestWriter instances are
4522+ * remembered accross reloads.
4523+ *
4524+ **/
4525+static void
4526+affile_dd_reuse_writer(gpointer key, gpointer value, gpointer user_data)
4527+{
4528+ AFFileDestDriver *self = (AFFileDestDriver *) user_data;
4529+ AFFileDestWriter *writer = (AFFileDestWriter *) value;
4530+
4531+ affile_dw_set_owner(writer, self);
4532+ log_pipe_init(&writer->super, NULL);
4533+}
4534+
4535+
4536+static gboolean
4537+affile_dd_init(LogPipe *s)
4538+{
4539+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4540+ GlobalConfig *cfg = log_pipe_get_config(s);
4541+
4542+ if (!log_dest_driver_init_method(s))
4543+ return FALSE;
4544+
4545+ if (cfg->create_dirs)
4546+ self->flags |= AFFILE_CREATE_DIRS;
4547+ if (self->file_uid == -1)
4548+ self->file_uid = cfg->file_uid;
4549+ if (self->file_gid == -1)
4550+ self->file_gid = cfg->file_gid;
4551+ if (self->file_perm == -1)
4552+ self->file_perm = cfg->file_perm;
4553+ if (self->dir_uid == -1)
4554+ self->dir_uid = cfg->dir_uid;
4555+ if (self->dir_gid == -1)
4556+ self->dir_gid = cfg->dir_gid;
4557+ if (self->dir_perm == -1)
4558+ self->dir_perm = cfg->dir_perm;
4559+ if (self->time_reap == -1)
4560+ self->time_reap = cfg->time_reap;
4561+
4562+ log_writer_options_init(&self->writer_options, cfg, 0);
4563+ log_template_options_init(&self->template_fname_options, cfg);
4564+
4565+ if ((self->flags & AFFILE_NO_EXPAND) == 0)
4566+ {
4567+ self->writer_hash = cfg_persist_config_fetch(cfg, affile_dd_format_persist_name(self));
4568+ if (self->writer_hash)
4569+ g_hash_table_foreach(self->writer_hash, affile_dd_reuse_writer, self);
4570+ }
4571+ else
4572+ {
4573+ self->single_writer = cfg_persist_config_fetch(cfg, affile_dd_format_persist_name(self));
4574+ if (self->single_writer)
4575+ {
4576+ affile_dw_set_owner(self->single_writer, self);
4577+ log_pipe_init(&self->single_writer->super, cfg);
4578+ }
4579+ }
4580+
4581+
4582+ return TRUE;
4583+}
4584+
4585+
4586+/**
4587+ * This is registered as a destroy-notify callback for an AFFileDestWriter
4588+ * instance. It destructs and frees the writer instance.
4589+ **/
4590+static void
4591+affile_dd_destroy_writer(gpointer value)
4592+{
4593+ AFFileDestWriter *writer = (AFFileDestWriter *) value;
4594+
4595+ main_loop_assert_main_thread();
4596+ log_pipe_deinit(&writer->super);
4597+ log_pipe_unref(&writer->super);
4598+}
4599+
4600+/*
4601+ * This function is called as a g_hash_table_foreach_remove() callback to
4602+ * free the specific AFFileDestWriter instance in the hashtable.
4603+ */
4604+static gboolean
4605+affile_dd_destroy_writer_hr(gpointer key, gpointer value, gpointer user_data)
4606+{
4607+ affile_dd_destroy_writer(value);
4608+ return TRUE;
4609+}
4610+
4611+/**
4612+ * affile_dd_destroy_writer_hash:
4613+ * @value: GHashTable instance passed as a generic pointer
4614+ *
4615+ * Destroy notify callback for the GHashTable storing AFFileDestWriter instances.
4616+ **/
4617+static void
4618+affile_dd_destroy_writer_hash(gpointer value)
4619+{
4620+ GHashTable *writer_hash = (GHashTable *) value;
4621+
4622+ g_hash_table_foreach_remove(writer_hash, affile_dd_destroy_writer_hr, NULL);
4623+ g_hash_table_destroy(writer_hash);
4624+}
4625+
4626+static void
4627+affile_dd_deinit_writer(gpointer key, gpointer value, gpointer user_data)
4628+{
4629+ log_pipe_deinit((LogPipe *) value);
4630+}
4631+
4632+static gboolean
4633+affile_dd_deinit(LogPipe *s)
4634+{
4635+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4636+ GlobalConfig *cfg = log_pipe_get_config(s);
4637+ /* NOTE: we free all AFFileDestWriter instances here as otherwise we'd
4638+ * have circular references between AFFileDestDriver and file writers */
4639+ if (self->single_writer)
4640+ {
4641+ g_assert(self->writer_hash == NULL);
4642+
4643+ log_pipe_deinit(&self->single_writer->super);
4644+ cfg_persist_config_add(cfg, affile_dd_format_persist_name(self), self->single_writer, affile_dd_destroy_writer, FALSE);
4645+ self->single_writer = NULL;
4646+ }
4647+ else if (self->writer_hash)
4648+ {
4649+ g_assert(self->single_writer == NULL);
4650+
4651+ g_hash_table_foreach(self->writer_hash, affile_dd_deinit_writer, NULL);
4652+ cfg_persist_config_add(cfg, affile_dd_format_persist_name(self), self->writer_hash, affile_dd_destroy_writer_hash, FALSE);
4653+ self->writer_hash = NULL;
4654+ }
4655+
4656+ if (!log_dest_driver_deinit_method(s))
4657+ return FALSE;
4658+
4659+ return TRUE;
4660+}
4661+
4662+/*
4663+ * This function is ran in the main thread whenever a writer is not yet
4664+ * instantiated. Returns a reference to the newly constructed LogPipe
4665+ * instance where the caller needs to forward its message.
4666+ */
4667+static LogPipe *
4668+affile_dd_open_writer(gpointer args[])
4669+{
4670+ AFFileDestDriver *self = args[0];
4671+ GlobalConfig *cfg = log_pipe_get_config(&self->super.super.super);
4672+ AFFileDestWriter *next;
4673+
4674+ main_loop_assert_main_thread();
4675+ if (self->flags & AFFILE_NO_EXPAND)
4676+ {
4677+ if (!self->single_writer)
4678+ {
4679+ next = affile_dw_new(self, self->filename_template->template);
4680+ if (next && log_pipe_init(&next->super, cfg))
4681+ {
4682+ log_pipe_ref(&next->super);
4683+ g_static_mutex_lock(&self->lock);
4684+ self->single_writer = next;
4685+ g_static_mutex_unlock(&self->lock);
4686+ }
4687+ else
4688+ {
4689+ log_pipe_unref(&next->super);
4690+ next = NULL;
4691+ }
4692+ }
4693+ else
4694+ {
4695+ next = self->single_writer;
4696+ log_pipe_ref(&next->super);
4697+ }
4698+ }
4699+ else
4700+ {
4701+ GString *filename = args[1];
4702+
4703+ /* hash table construction is serialized, as we only do that in the main thread. */
4704+ if (!self->writer_hash)
4705+ self->writer_hash = g_hash_table_new(g_str_hash, g_str_equal);
4706+
4707+ /* we don't need to lock the hashtable as it is only written in
4708+ * the main thread, which we're running right now. lookups in
4709+ * other threads must be locked. writers must be locked even in
4710+ * this thread to exclude lookups in other threads. */
4711+
4712+ next = g_hash_table_lookup(self->writer_hash, filename->str);
4713+ if (!next)
4714+ {
4715+ next = affile_dw_new(self, filename->str);
4716+ if (!log_pipe_init(&next->super, cfg))
4717+ {
4718+ log_pipe_unref(&next->super);
4719+ next = NULL;
4720+ }
4721+ else
4722+ {
4723+ log_pipe_ref(&next->super);
4724+ g_static_mutex_lock(&self->lock);
4725+ g_hash_table_insert(self->writer_hash, next->filename, next);
4726+ g_static_mutex_unlock(&self->lock);
4727+ }
4728+ }
4729+ else
4730+ {
4731+ log_pipe_ref(&next->super);
4732+ }
4733+ }
4734+
4735+ if (next)
4736+ {
4737+ next->queue_pending = TRUE;
4738+ /* we're returning a reference */
4739+ return &next->super;
4740+ }
4741+ return NULL;
4742+}
4743+
4744+static void
4745+affile_dd_queue(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options, gpointer user_data)
4746+{
4747+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4748+ AFFileDestWriter *next;
4749+ gpointer args[2] = { self, NULL };
4750+
4751+ if (self->flags & AFFILE_NO_EXPAND)
4752+ {
4753+ /* no need to lock the check below, the worst case that happens is
4754+ * that we go to the mainloop to return the same information, but this
4755+ * is not fast path anyway */
4756+
4757+ g_static_mutex_lock(&self->lock);
4758+ if (!self->single_writer)
4759+ {
4760+ g_static_mutex_unlock(&self->lock);
4761+ next = main_loop_call((void *(*)(void *)) affile_dd_open_writer, args, TRUE);
4762+ }
4763+ else
4764+ {
4765+ /* we need to lock single_writer in order to get a reference and
4766+ * make sure it is not a stale pointer by the time we ref it */
4767+ next = self->single_writer;
4768+ next->queue_pending = TRUE;
4769+ log_pipe_ref(&next->super);
4770+ g_static_mutex_unlock(&self->lock);
4771+ }
4772+ }
4773+ else
4774+ {
4775+ GString *filename;
4776+
4777+ filename = g_string_sized_new(32);
4778+ log_template_format(self->filename_template, msg, &self->template_fname_options, LTZ_LOCAL, 0, NULL, filename);
4779+
4780+ g_static_mutex_lock(&self->lock);
4781+ if (self->writer_hash)
4782+ next = g_hash_table_lookup(self->writer_hash, filename->str);
4783+ else
4784+ next = NULL;
4785+
4786+ if (next)
4787+ {
4788+ log_pipe_ref(&next->super);
4789+ next->queue_pending = TRUE;
4790+ g_static_mutex_unlock(&self->lock);
4791+ }
4792+ else
4793+ {
4794+ g_static_mutex_unlock(&self->lock);
4795+ args[1] = filename;
4796+ next = main_loop_call((void *(*)(void *)) affile_dd_open_writer, args, TRUE);
4797+ }
4798+ g_string_free(filename, TRUE);
4799+ }
4800+ if (next)
4801+ {
4802+ log_pipe_queue(&next->super, msg, path_options);
4803+ next->queue_pending = FALSE;
4804+ log_pipe_unref(&next->super);
4805+ }
4806+ else
4807+ log_msg_drop(msg, path_options);
4808+}
4809+
4810+static void
4811+affile_dd_free(LogPipe *s)
4812+{
4813+ AFFileDestDriver *self = (AFFileDestDriver *) s;
4814+
4815+ /* NOTE: this must be NULL as deinit has freed it, otherwise we'd have circular references */
4816+ g_assert(self->single_writer == NULL && self->writer_hash == NULL);
4817+
4818+ log_template_options_destroy(&self->template_fname_options);
4819+ log_template_unref(self->filename_template);
4820+ log_writer_options_destroy(&self->writer_options);
4821+ log_dest_driver_free(s);
4822+}
4823+
4824+LogDriver *
4825+affile_dd_new(gchar *filename, guint32 flags)
4826+{
4827+ AFFileDestDriver *self = g_new0(AFFileDestDriver, 1);
4828+
4829+ log_dest_driver_init_instance(&self->super);
4830+ self->super.super.super.init = affile_dd_init;
4831+ self->super.super.super.deinit = affile_dd_deinit;
4832+ self->super.super.super.queue = affile_dd_queue;
4833+ self->super.super.super.free_fn = affile_dd_free;
4834+ self->filename_template = log_template_new(configuration, NULL);
4835+ log_template_compile(self->filename_template, filename, NULL);
4836+ self->flags = flags;
4837+ self->file_uid = self->file_gid = -1;
4838+ self->file_perm = -1;
4839+ self->dir_uid = self->dir_gid = -1;
4840+ self->dir_perm = -1;
4841+ log_writer_options_defaults(&self->writer_options);
4842+ if (strchr(filename, '$') == NULL)
4843+ {
4844+ self->flags |= AFFILE_NO_EXPAND;
4845+ }
4846+ self->time_reap = -1;
4847+ log_template_options_defaults(&self->template_fname_options);
4848+ g_static_mutex_init(&self->lock);
4849+ return &self->super.super;
4850+}
4851
4852=== added directory '.pc/afsocket-Fix-compilation-with-libsystemd-daemon.patch'
4853=== added file '.pc/afsocket-Fix-compilation-with-libsystemd-daemon.patch/configure.in'
4854--- .pc/afsocket-Fix-compilation-with-libsystemd-daemon.patch/configure.in 1970-01-01 00:00:00 +0000
4855+++ .pc/afsocket-Fix-compilation-with-libsystemd-daemon.patch/configure.in 2011-11-16 01:25:28 +0000
4856@@ -0,0 +1,1184 @@
4857+dnl Process this file with autoconf to produce a configure script.
4858+dnl
4859+dnl There are a couple of environment defined variables which this script
4860+dnl makes use of in addition to the standard CFLAGS/LDFLAGS/etc. These are:
4861+dnl
4862+dnl RELEASE_TAG - Debian release tag which is put to debian/changelog
4863+dnl SNAPSHOT_VERSION - snapshot version to add to version number
4864+dnl BINARY_BRANCH - the value is added to all source/binary packages
4865+dnl SOURCE_REVISION - Revision of the source-tree, will added to the version string
4866+dnl
4867+AC_INIT(syslog-ng/main.c)
4868+AC_CONFIG_MACRO_DIR([m4])
4869+
4870+dnl ***************************************************************************
4871+dnl definitions
4872+
4873+PACKAGE="syslog-ng"
4874+VERSION="`cat $srcdir/VERSION`"
4875+
4876+dnl ***************************************************************************
4877+dnl dependencies
4878+
4879+GLIB_MIN_VERSION="2.10.1"
4880+EVTLOG_MIN_VERSION="0.2.12"
4881+OPENSSL_MIN_VERSION="0.9.8"
4882+LIBDBI_MIN_VERSION="0.8.0"
4883+IVYKIS_MIN_VERSION="0.18"
4884+JSON_C_MIN_VERSION="0.7"
4885+JSON_GLIB_MIN_VERSION="0.12"
4886+PCRE_MIN_VERSION="6.1"
4887+LMC_MIN_VERSION="0.1.0"
4888+
4889+dnl ***************************************************************************
4890+dnl Initial setup
4891+
4892+ostype=`uname -s`
4893+
4894+if test -r $srcdir/dist.conf; then
4895+ # read defaults, dist.conf does not change
4896+ # values for parameters that are already set
4897+ . $srcdir/dist.conf
4898+fi
4899+
4900+if test -z "$RELEASE_TAG"; then
4901+ RELEASE_TAG=unstable
4902+fi
4903+
4904+
4905+if test "`uname -s`" = "Linux";then
4906+ CURRDATE=`date -R`
4907+else
4908+ CURRDATE=`date +"%a, %d %b %Y %H:%M:%S %Z"`
4909+fi
4910+
4911+AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define)
4912+_AM_PROG_TAR([ustar])
4913+if test -n "$SNAPSHOT_VERSION"; then
4914+ VERSION=$VERSION+$SNAPSHOT_VERSION
4915+fi
4916+
4917+if test "x$prefix" = "xNONE"; then
4918+ prefix=$ac_default_prefix
4919+fi
4920+if test "x$exec_prefix" = "xNONE"; then
4921+ exec_prefix='${prefix}'
4922+fi
4923+pidfiledir='${localstatedir}'
4924+moduledir='${exec_prefix}/lib/syslog-ng'
4925+
4926+AM_CONFIG_HEADER(config.h)
4927+
4928+dnl ***************************************************************************
4929+dnl Arguments
4930+
4931+AC_ARG_WITH(libnet,
4932+ [ --with-libnet=path use path to libnet-config script],
4933+ ,
4934+ [with_libnet=""])
4935+
4936+AC_ARG_WITH(pidfile-dir,
4937+ [ --with-pidfile-dir=path Use path as the directory for storing pidfiles],
4938+ pidfiledir=$with_pidfile_dir)
4939+
4940+AC_ARG_WITH(module-dir,
4941+ [ --with-module-dir=path Use path as the directory to install modules into],
4942+ moduledir=$with_module_dir)
4943+
4944+AC_ARG_WITH(module-path,
4945+ [ --with-module-path=path Use path as the list of ':' separated directories looked up when searching for modules],
4946+ module_path=$with_module_path)
4947+
4948+AC_ARG_WITH(timezone-dir,
4949+ [ --with-timezone-dir=path Use path as the directory to get the timezone files],
4950+ timezonedir=$with_timezone_dir)
4951+
4952+AC_ARG_WITH(default-modules,
4953+ [ --with-default-modules="mod1,mod2,mod3" Use these as the list of automatically loaded modules],
4954+ default_modules=$with_default_modules, default_modules="auto")
4955+
4956+AC_ARG_WITH(ld-library-path,
4957+ [ --with-ld-library-path=path Set LD_LIBRARY_PATH during runtime to the value given],
4958+ env_ld_library_path=$with_ld_library_path)
4959+
4960+AC_ARG_WITH([systemdsystemunitdir],
4961+ AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]))
4962+
4963+AC_ARG_ENABLE(debug,
4964+ [ --enable-debug Enable debugging code.],, enable_debug="no")
4965+
4966+AC_ARG_ENABLE(env-wrapper,
4967+ [ --enable-env-wrapper Enable wrapper program to set up various environment variables],, enable_env_wrapper=auto)
4968+
4969+AC_ARG_ENABLE(gprof,
4970+ [ --enable-gprof Enable gcc profiling.],, enable_gprof="no")
4971+
4972+AC_ARG_ENABLE(memtrace,
4973+ [ --enable-memtrace Enable alternative leak debugging code.])
4974+
4975+AC_ARG_ENABLE(ssl,
4976+ [ --enable-ssl Enable SSL support.],,enable_ssl="auto")
4977+
4978+AC_ARG_ENABLE(dynamic-linking,
4979+ [ --enable-dynamic-linking Link everything dynamically.],,enable_dynamic_linking="auto")
4980+
4981+AC_ARG_ENABLE(mixed-linking,
4982+ [ --enable-mixed-linking Link 3rd party libraries statically, system libraries dynamically],,enable_mixed_linking="auto")
4983+
4984+AC_ARG_ENABLE(ipv6,
4985+ [ --enable-ipv6 Enable support for IPv6.],,enable_ipv6="auto")
4986+
4987+AC_ARG_ENABLE(tcp-wrapper,
4988+ [ --enable-tcp-wrapper Enable support for TCP wrappers.],,enable_tcp_wrapper="auto")
4989+
4990+AC_ARG_ENABLE(spoof-source,
4991+ [ --enable-spoof-source Enable support for spoofed source addresses.]
4992+ ,,enable_spoof_source="auto")
4993+
4994+AC_ARG_ENABLE(sun-streams,
4995+ [ --enable-sun-streams Enable support for Solaris /dev/log STREAMS device.]
4996+ ,,enable_sun_streams="auto")
4997+
4998+AC_ARG_ENABLE(sql,
4999+ [ --enable-sql Enable support for SQL destinations. (default: auto)]
5000+ ,,enable_sql="auto")
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: