On Thu, Apr 09, 2015 at 11:43:15PM +0530, Susant Sahani wrote: > This tiny daemon enables to pull journal entries and push to a UDP > multicast address in syslog RFC 5424 format. systemd-journal-syslogd > runs with own user systemd-journal-syslog. It starts running after > the network is up. > > V2: Address Zbigniew's comments > 1. Rename binary systemd-journal-syslogd > 2. Fixed up man and added example > 3. Error code check sd_event_add_signal > 4. remove +User=systemd-journal-network from service file > 5. remove opterr=0 > 6. assignment into declaration of mh > > V3: Address Lennart's comments > 1. add unicast events in the man > 2. use fopen_temporary and fflush_and_check(). > 3. remove if (m->event_journal_input) { > 4. use sigprocmask_many > 5. fix facility and priority > 6. remove IP_MULTICAST_TTL and IP_PKTINFO > 7. use safe_atoi > --- > Makefile-man.am | 8 + > Makefile.am | 37 ++ > man/systemd-journal-syslogd.service.xml | 84 +++++ > man/systemd-journal-syslogd.xml | 156 ++++++++ > src/journal-remote/journal-syslog-conf.c | 61 ++++ > src/journal-remote/journal-syslog-conf.h | 39 ++ > src/journal-remote/journal-syslog-gperf.gperf | 18 + > src/journal-remote/journal-syslog-manager.c | 501 > ++++++++++++++++++++++++++ > src/journal-remote/journal-syslog-manager.h | 70 ++++ > src/journal-remote/journal-syslog-network.c | 201 +++++++++++ > src/journal-remote/journal-syslogd.c | 217 +++++++++++ > src/journal-remote/journal-syslogd.conf.in | 2 + > units/systemd-journal-syslogd.service | 18 + > 13 files changed, 1412 insertions(+) > create mode 100644 man/systemd-journal-syslogd.service.xml > create mode 100644 man/systemd-journal-syslogd.xml > create mode 100644 src/journal-remote/journal-syslog-conf.c > create mode 100644 src/journal-remote/journal-syslog-conf.h > create mode 100644 src/journal-remote/journal-syslog-gperf.gperf > create mode 100644 src/journal-remote/journal-syslog-manager.c > create mode 100644 src/journal-remote/journal-syslog-manager.h > create mode 100644 src/journal-remote/journal-syslog-network.c > create mode 100644 src/journal-remote/journal-syslogd.c > create mode 100644 src/journal-remote/journal-syslogd.conf.in > create mode 100644 units/systemd-journal-syslogd.service > > diff --git a/Makefile-man.am b/Makefile-man.am > index 2f3e5f2..437d488 100644 > --- a/Makefile-man.am > +++ b/Makefile-man.am > @@ -1380,6 +1380,14 @@ man/systemd-journal-gatewayd.socket.html: > man/systemd-journal-gatewayd.service.h > > endif > > +MANPAGES += \ > + man/systemd-journal-syslogd.service.8 \ > + man/systemd-journal-syslogd.8 > +MANPAGES_ALIAS += \ > + man/systemd-journal-syslogd.8 > +man/systemd-journal-syslogd.8: man/systemd-journal-syslogd.service.8 > +man/systemd-journal-syslogd.html: man/systemd-journal-syslogd.service.html > + > if HAVE_MYHOSTNAME > MANPAGES += \ > man/nss-myhostname.8 > diff --git a/Makefile.am b/Makefile.am > index 0a57389..0b843ac 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -4361,6 +4361,43 @@ EXTRA_DIST += \ > src/journal-remote/journal-upload.conf.in > endif > > +systemd_journal_syslogd_SOURCES = \ > + src/journal-remote/journal-syslog-manager.h \ > + src/journal-remote/journal-syslog-manager.c \ > + src/journal-remote/journal-syslog-conf.h \ > + src/journal-remote/journal-syslog-conf.c \ > + src/journal-remote/journal-syslog-network.c \ > + src/journal-remote/journal-syslogd.c > + > +nodist_systemd_journal_syslogd_SOURCES = \ > + src/journal-remote/journal-syslog-gperf.c > + > +EXTRA_DIST += \ > + src/journal-remote/journal-syslog-gperf.gperf > + > +CLEANFILES += \ > + src/journal-remote/journal-syslog-gperf.c > + > +systemd_journal_syslogd_LDADD = \ > + libsystemd-internal.la \ > + libsystemd-journal-internal.la \ > + libsystemd-shared.la > + > +rootlibexec_PROGRAMS += \ > + systemd-journal-syslogd > + > +nodist_systemunit_DATA += \ > + units/systemd-journal-syslogd.service > + > +EXTRA_DIST += \ > + units/systemd-journal-syslogd.service.in > + > +nodist_pkgsysconf_DATA += \ > + src/journal-remote/journal-syslogd.conf > + > +EXTRA_DIST += \ > + src/journal-remote/journal-syslogd.conf.in > + > # using _CFLAGS = in the conditional below would suppress AM_CFLAGS > journalctl_CFLAGS = \ > $(AM_CFLAGS) > diff --git a/man/systemd-journal-syslogd.service.xml > b/man/systemd-journal-syslogd.service.xml > new file mode 100644 > index 0000000..e837153 > --- /dev/null > +++ b/man/systemd-journal-syslogd.service.xml > @@ -0,0 +1,84 @@ > +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; > indent-tabs-mode: nil -*--> > +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" > +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> > + > +<!-- > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +--> > + > +<refentry id="systemd-journal-syslogd.service" > xmlns:xi="http://www.w3.org/2001/XInclude"> > + > + <refentryinfo> > + <title>systemd-journal-syslogd.service</title> > + <productname>systemd</productname> > + > + <authorgroup> > + <author> > + <contrib>Developer</contrib> > + <firstname>Susant</firstname> > + <surname>Sahani</surname> > + <email>ssah...@gmail.com</email> > + </author> > + </authorgroup> > + </refentryinfo> > + > + <refmeta> > + <refentrytitle>systemd-journal-syslogd.service</refentrytitle> > + <manvolnum>8</manvolnum> > + </refmeta> > + > + <refnamediv> > + <refname>systemd-journal-syslogd.service</refname> > + <refname>systemd-journal-syslogd</refname> > + <refpurpose>Forward journal events using syslog network > procotol</refpurpose> > + </refnamediv> > + > + <refsynopsisdiv> > + <para><filename>systemd-journal-syslogd.service</filename></para> > + <cmdsynopsis> > + <command>/usr/lib/systemd/systemd-journal-syslogd</command> > + <arg choice="opt" rep="repeat">OPTIONS</arg> > + </cmdsynopsis> > + </refsynopsisdiv> > + > + <refsect1> > + <title>Description</title> > + > + <para><command>systemd-journal-syslogd</command> serves journal > + events over the network. It unicasts and multicasts journal event to > Syslog RFC 5424 format. "serves" is bad, because it implies clients connecting to it. Maybe something like this:
<command>systemd-journal-syslogd</command> forwards messages from the journal to other hosts over the network using the traditional syslog format following <ulink url="">RFC 5425</>. It can be configured to send messages to both unicast and multicast addresses. > + </para> > + > + <para>The program is started by > + > <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> > + . Use The dot should go right after ">". Otherwise there'll be extra spaces in the formatted output. Why is there a separate man page for systemd-journal-syslogd? The one for systemd-journal-syslogd should be enough, it is not indended to be run standalone. There's useful stuff in the other one, please merge them! There should be two man pages: one for the binary and the service, and the other one for the config file. systemd-journal-syslogd -h does not work, it fails if the user name cannot be resolved. But --help should work regardless. > + <command>systemctl start systemd-journal-syslogd.service</command> to > start > + the service, and <command>systemctl enable > systemd-journal-syslogd.service</command> > + to have it started on boot.</para> > + </refsect1> > + > + <refsect1> > + <title>See Also</title> > + <para> > + > <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, > + > <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, > + > <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, > + > <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>, Trailing comma should be a dot. > + </para> > + </refsect1> > + > +</refentry> > diff --git a/man/systemd-journal-syslogd.xml b/man/systemd-journal-syslogd.xml > new file mode 100644 > index 0000000..5497b2e > --- /dev/null > +++ b/man/systemd-journal-syslogd.xml > @@ -0,0 +1,156 @@ > +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; > indent-tabs-mode: nil -*--> > +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" > +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> > + > +<!-- > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +--> > + > +<refentry id="systemd-journal-syslogd" > xmlns:xi="http://www.w3.org/2001/XInclude"> > + <refentryinfo> > + <title>systemd-journal-syslogd</title> > + <productname>systemd</productname> > + > + <authorgroup> > + <author> > + <contrib>Developer</contrib> > + <firstname>Susant</firstname> > + <surname>Sahani</surname> > + <email>ssah...@gmail.com</email> > + </author> > + </authorgroup> > + </refentryinfo> > + > + <refmeta> > + <refentrytitle>systemd-journal-syslogd</refentrytitle> > + <manvolnum>8</manvolnum> > + </refmeta> > + > + <refnamediv> > + <refname>systemd-journal-syslogd</refname> > + <refpurpose>Send journal messages over the network in RFC 5424 > format</refpurpose> > + </refnamediv> > + > + <refsynopsisdiv> > + <cmdsynopsis> > + <command>systemd-journal-syslogd</command> > + <arg choice="opt" rep="repeat">OPTIONS</arg> > + <arg choice="opt" rep="norepeat">--save-state=<replaceable>state > file</replaceable></arg> > + <arg choice="opt" rep="norepeat">--cursor=<replaceable>journal > cursor</replaceable></arg> > + </cmdsynopsis> > + </refsynopsisdiv> > + > + <refsect1> > + <title>Description</title> > + > + <para> > + <command>systemd-journal-syslogd</command> will send journal > + entries to the UDP Unicast and Multicast address . Unless > + limited by one of the options specified below, all journal > + entries accessible to the user the program is running as will be > + sent, and then the program will wait and send new entries > + as they become available. > + </para> > + </refsect1> > + > + <refsect1> > + <title>Options</title> > + > + <variablelist> > + <varlistentry> > + <term><option>--cursor=</option></term> > + > + <listitem><para>Send entries from the location in the > + journal specified by the passed cursor. This has the same > + meaning as <option>--cursor</option> option for > + > <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem> > + </varlistentry> > + > + <varlistentry> > + > <term><option>--save-state</option><optional>=<replaceable>PATH</replaceable></optional></term> > + > + <listitem><para>Send entries from the location in the > + journal <emphasis>after</emphasis> the location specified by > + the cursor saved in file at <replaceable>PATH</replaceable> > + (<filename>/var/lib/systemd/journal-syslogd/state</filename> by > default). > + After an entry is successfully uploaded, update this file > + with the cursor of that entry. > + </para></listitem> > + </varlistentry> > + > + <xi:include href="standard-options.xml" xpointer="help" /> > + <xi:include href="standard-options.xml" xpointer="version" /> > + </variablelist> > + </refsect1> > + > + <refsect1> > + <title>Exit status</title> > + > + <para>On success, 0 is returned; otherwise, a non-zero > + failure code is returned.</para> > + </refsect1> > + > + <refsect1> > + <title>[Network] Section Options</title> > + > + <para>The <literal>[Network]</literal> section only applies for > + UDP multicast address and Port:</para> > + > + <variablelist class='network-directives'> > + <varlistentry> > + <term><varname>Address=</varname></term> > + <listitem><para>Controls whether log messages received by the > + journal daemon shall be forwarded to a unicast UDP address or > multicast UDP network > + group in syslog RFC 5424 format.</para> > + > + <para>The the address string format is similar to socket units. See > + > <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>1</manvolnum></citerefentry> > + </para> > + </listitem> > + </varlistentry> > + </variablelist> > + </refsect1> > + > + <refsect1> > + <title>Example</title> > + <example> > + <title>/etc/systemd/journal-syslogd.conf</title> > + <programlisting>[Network] > +Address=239.0.0.1:6000 > + </programlisting> > + </example> > + </refsect1> > + > + <refsect1> > + <title>Example</title> > + <example> > + <title>/etc/systemd/journal-syslogd.conf</title> > + <programlisting>[Network] > +Address=192.168.8.101:514 > + </programlisting> > + </example> > + </refsect1> > + > + <refsect1> > + <title>See Also</title> > + <para> > + > <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, > + > <citerefentry><refentrytitle>systemd-journal-syslogd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, > + </para> > + </refsect1> > +</refentry> > diff --git a/src/journal-remote/journal-syslog-conf.c > b/src/journal-remote/journal-syslog-conf.c > new file mode 100644 > index 0000000..c357189 > --- /dev/null > +++ b/src/journal-remote/journal-syslog-conf.c > @@ -0,0 +1,61 @@ > +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ > + > +/*** > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +***/ > + > +#include "in-addr-util.h" > +#include "journal-syslog-conf.h" > + > +int config_parse_syslog_broadcast_address(const char *unit, > + const char *filename, > + unsigned line, > + const char *section, > + unsigned section_line, > + const char *lvalue, > + int ltype, > + const char *rvalue, > + void *data, > + void *userdata) { > + Manager *m = userdata; > + int r; > + > + assert(filename); > + assert(lvalue); > + assert(rvalue); > + assert(data); > + > + r = socket_address_parse(&m->address, rvalue); > + if (r < 0) { > + log_syntax(unit, LOG_ERR, filename, line, -r, > + "Failed to parse address value, ignoring: %s", > rvalue); > + return 0; > + } > + > + return 0; > +} > + > +int manager_parse_config_file(Manager *m) { > + assert(m); > + > + return config_parse_many("/etc/systemd/journal-syslogd.conf", > + > CONF_DIRS_NULSTR("systemd/journal-syslogd.conf"), > + "Network\0", > + config_item_perf_lookup, > journal_syslog_gperf_lookup, > + false, m); > +} > diff --git a/src/journal-remote/journal-syslog-conf.h > b/src/journal-remote/journal-syslog-conf.h > new file mode 100644 > index 0000000..ca9ef05 > --- /dev/null > +++ b/src/journal-remote/journal-syslog-conf.h > @@ -0,0 +1,39 @@ > +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ > + > +/*** > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +***/ > + > +#pragma once > + > +#include "in-addr-util.h" > +#include "conf-parser.h" > +#include "journal-syslog-manager.h" > + > +const struct ConfigPerfItem* journal_syslog_gperf_lookup(const char *key, > unsigned length); > +int config_parse_syslog_broadcast_address(const char *unit, > + const char *filename, > + unsigned line, > + const char *section, > + unsigned section_line, > + const char *lvalue, > + int ltype, > + const char *rvalue, > + void *data, > + void *userdata); > +int manager_parse_config_file(Manager *m); > diff --git a/src/journal-remote/journal-syslog-gperf.gperf > b/src/journal-remote/journal-syslog-gperf.gperf > new file mode 100644 > index 0000000..e0f364f > --- /dev/null > +++ b/src/journal-remote/journal-syslog-gperf.gperf > @@ -0,0 +1,18 @@ > +%{ > +#include <stddef.h> > +#include "conf-parser.h" > +#include "journal-syslog-conf.h" > +#include "journal-syslog-manager.h" > +%} > +struct ConfigPerfItem; > +%null_strings > +%language=ANSI-C > +%define slot-name section_and_lvalue > +%define hash-function-name journal_syslog_gperf_hash > +%define lookup-function-name journal_syslog_gperf_lookup > +%readonly-tables > +%omit-struct-type > +%struct-type > +%includes > +%% > +Network.Address, config_parse_syslog_broadcast_address, 0, 0 > diff --git a/src/journal-remote/journal-syslog-manager.c > b/src/journal-remote/journal-syslog-manager.c > new file mode 100644 > index 0000000..1051f2d > --- /dev/null > +++ b/src/journal-remote/journal-syslog-manager.c > @@ -0,0 +1,501 @@ > +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ > + > +/*** > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +***/ > + > +#include "util.h" > +#include "socket-util.h" > +#include "conf-parser.h" > +#include "sd-daemon.h" > +#include "network-util.h" > +#include "capability.h" > +#include "mkdir.h" > +#include "fileio.h" > +#include "journal-internal.h" > +#include "journal-syslog-manager.h" > + > +#define JOURNAL_SEND_POLL_TIMEOUT (10 * USEC_PER_SEC) > + > +/* Default severity LOG_NOTICE */ > +#define JOURNAL_DEFAULT_SEVERITY LOG_PRI(LOG_NOTICE) > + > +/* Default facility LOG_USER */ > +#define JOURNAL_DEFAULT_FACILITY LOG_FAC(LOG_USER) > + > +static int parse_field(const void *data, size_t length, const char *field, > char **target, size_t *target_size) { > + size_t fl, nl; > + void *buf; > + > + assert(data); > + assert(field); > + assert(target); > + assert(target_size); > + > + fl = strlen(field); > + if (length < fl) > + return 0; > + > + if (memcmp(data, field, fl)) > + return 0; > + > + nl = length - fl; > + buf = malloc(nl+1); > + if (!buf) > + return -ENOMEM; > + > + memcpy(buf, (const char*) data + fl, nl); > + ((char*)buf)[nl] = 0; > + > + free(*target); > + *target = buf; > + *target_size = nl; > + > + return 1; > +} > + > +static int manager_read_journal_input(Manager *m) { > + _cleanup_free_ char *facility = NULL, *identifier = NULL, > + *priority = NULL, *message = NULL, *pid = NULL, > + *hostname = NULL; > + int sev = JOURNAL_DEFAULT_SEVERITY; > + int fac = JOURNAL_DEFAULT_FACILITY; > + struct timeval tv; > + usec_t realtime; > + const void *data; > + size_t length; > + size_t n = 0; > + int r; > + > + assert(m); > + assert(m->journal); > + > + JOURNAL_FOREACH_DATA_RETVAL(m->journal, data, length, r) { > + > + r = parse_field(data, length, "PRIORITY=", &priority, &n); Is n used for anything? > + if (r < 0) > + return r; > + else if (r > 0) > + continue; > + > + r = parse_field(data, length, "SYSLOG_FACILITY=", &facility, > &n); > + if (r < 0) > + return r; > + else if (r > 0) > + continue; > + > + r = parse_field(data, length, "_HOSTNAME=", &hostname, &n); > + if (r < 0) > + return r; > + else if (r > 0) > + continue; > + > + r = parse_field(data, length, "SYSLOG_IDENTIFIER=", > &identifier, &n); > + if (r < 0) > + return r; > + else if (r > 0) > + continue; > + > + r = parse_field(data, length, "_PID=", &pid, &n); > + if (r < 0) > + return r; > + else if (r > 0) > + continue; > + > + r = parse_field(data, length, "MESSAGE=", &message, &n); > + if (r < 0) > + return r; > + } > + > + r = sd_journal_get_realtime_usec(m->journal, &realtime); > + if (r < 0) > + log_warning_errno(r, "Failed to rerieve realtime from > journal: %m"); > + else { > + tv.tv_sec = realtime / USEC_PER_SEC; > + tv.tv_usec = realtime % USEC_PER_SEC; > + } > + > + if (facility) { > + r = safe_atoi(facility, &fac); safe_atou? > + if (r < 0) > + log_debug("Failed to parse syslog facility: %s", > facility); > + > + if (fac < LOG_KERN || fac >= LOG_NFACILITIES) > + fac = JOURNAL_DEFAULT_FACILITY; > + } > + > + if (priority) { > + r = safe_atoi(priority, &sev); safe_atou? > + if (r < 0) > + log_debug("Failed to parse syslog priority: %s", > priority); > + > + if (sev < LOG_EMERG || sev > LOG_DEBUG) > + sev = JOURNAL_DEFAULT_SEVERITY; > + } > + > + return manager_push_to_network(m, sev, fac, identifier, > + message, hostname, pid, r >= 0 ? &tv > : NULL); > +} > + > +static int update_cursor_state(Manager *m) { > + _cleanup_free_ char *temp_path = NULL; > + _cleanup_fclose_ FILE *f = NULL; > + int r; > + > + assert(m); > + > + if (!m->state_file || !m->last_cursor) > + return 0; > + > + r = fopen_temporary(m->state_file, &f, &temp_path); > + if (r < 0) > + goto finish; > + > + fchmod(fileno(f), 0644); > + > + fprintf(f, > + "# This is private data. Do not parse.\n" > + "LAST_CURSOR=%s\n", > + m->last_cursor); > + > + r = fflush_and_check(f); > + if (r < 0) > + goto finish; > + > + if (rename(temp_path, m->state_file) < 0) { > + r = -errno; > + goto finish; > + } > + > + free(temp_path); > + temp_path = NULL; Why is this freed here? Shouldn't it always be freed, in the error path too? > + finish: > + if (r < 0) > + log_error_errno(r, "Failed to save state %s: %m", > m->state_file); > + > + return r; > +} > + > +static int load_cursor_state(Manager *m) { > + int r; > + > + assert(m); > + > + if (!m->state_file) > + return 0; > + > + r = parse_env_file(m->state_file, NEWLINE, "LAST_CURSOR", > &m->last_cursor, NULL); > + if (r < 0 && r != -ENOENT) > + return r; > + > + log_debug("Last cursor was %s.", m->last_cursor ? m->last_cursor : > "Not available"); "Not available" → "not available". > + return 0; > +} > + > +static int process_journal_input(Manager *m) { > + int r; > + > + assert(m); > + assert(m->journal); > + > + while (true) { > + r = sd_journal_next(m->journal); > + if (r < 0) { > + log_error_errno(r, "Failed to get next entry: %m"); > + return r; > + } > + > + if (r == 0) > + break; > + > + r = manager_read_journal_input(m); > + if (r < 0) { > + /* Can't send the message. Seek one entry back. */ > + r = sd_journal_previous(m->journal); > + if (r < 0) > + log_error_errno(r, "Failed to iterate > through journal: %m"); > + > + break; > + } > + } > + > + r = sd_journal_get_cursor(m->journal, &m->current_cursor); > + if (r < 0) > + return log_error_errno(r, "Failed to get cursor: %m"); > + > + free(m->last_cursor); > + m->last_cursor = m->current_cursor; > + m->current_cursor = NULL; > + > + return update_cursor_state(m); > +} > + > +static int manager_journal_event_handler(sd_event_source *event, int fd, > uint32_t revents, void *userp) { > + Manager *m = userp; > + int r; > + > + if (revents & EPOLLHUP) { > + log_debug("Received HUP"); > + return 0; > + } > + > + if (!(revents & EPOLLIN)) { > + log_warning("Unexpected poll event %"PRIu32".", revents); > + return -EINVAL; > + } > + > + r = sd_journal_process(m->journal); > + if (r < 0) { > + log_error_errno(r, "Failed to process journal: %m"); > + manager_disconnect(m); > + return r; > + } > + > + if (r == SD_JOURNAL_NOP) > + return 0; > + > + return process_journal_input(m); > +} > + > +static void close_journal_input(Manager *m) { > + assert(m); > + > + if (m->journal) { > + log_debug("Closing journal input."); > + > + sd_journal_close(m->journal); > + m->journal = NULL; > + } > + > + m->timeout = 0; > +} > + > +static int manager_signal_event_handler(sd_event_source *event, const struct > signalfd_siginfo *si, void *userdata) { > + Manager *m = userdata; > + > + assert(m); > + > + log_received_signal(LOG_INFO, si); > + > + manager_disconnect(m); > + > + sd_event_exit(m->event, 0); > + > + return 0; > +} > + > +static int manager_journal_monitor_listen(Manager *m) { > + int r, events; > + > + assert(m); > + > + r = sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY); > + if (r < 0) { > + log_error_errno(r, "Failed to open journal: %m"); > + return r; > + } > + > + sd_journal_set_data_threshold(m->journal, 0); > + > + m->journal_watch_fd = sd_journal_get_fd(m->journal); > + if (m->journal_watch_fd < 0) > + return log_error_errno(m->journal_watch_fd, > "sd_journal_get_fd failed: %m"); > + > + events = sd_journal_get_events(m->journal); > + > + r = sd_journal_reliable_fd(m->journal); > + assert(r >= 0); > + if (r > 0) > + m->timeout = -1; > + else > + m->timeout = JOURNAL_SEND_POLL_TIMEOUT; > + > + r = sd_event_add_io(m->event, &m->event_journal_input , In some places there's strange indentation, like this space ^ before the comma, and also below. > + m->journal_watch_fd , events, > manager_journal_event_handler, m); > + if (r < 0) > + return log_error_errno(r, "Failed to register input event: > %m"); > + > + /* ignore failure */ > + if (!m->last_cursor) > + (void) load_cursor_state(m); > + > + if (m->last_cursor) { > + r = sd_journal_seek_cursor(m->journal, m->last_cursor); > + if (r < 0) > + return log_error_errno(r, "Failed to seek to cursor > %s: %m", > + m->last_cursor); > + } > + > + return 0; > +} > + > +int manager_connect(Manager *m) { > + int r; > + > + assert(m); > + > + manager_disconnect(m); > + > + r = manager_open_network_socket(m); > + if (r < 0) > + return r; > + > + r = manager_journal_monitor_listen(m); > + if (r < 0) > + return r; > + > + return 0; > +} > + > +void manager_disconnect(Manager *m) { > + assert(m); > + > + close_journal_input(m); > + > + manager_close_network_socket(m); > + > + m->event_journal_input = > sd_event_source_unref(m->event_journal_input); > + > + sd_notifyf(false, "STATUS=Idle."); > +} > + > +static int manager_network_event_handler(sd_event_source *s, int fd, > uint32_t revents, void *userdata) { > + Manager *m = userdata; > + bool connected, online; > + int r; > + > + assert(m); > + > + sd_network_monitor_flush(m->network_monitor); > + > + /* check if the machine is online */ > + online = network_is_online(); > + > + /* check if the socket is currently open*/ > + connected = m->socket >= 0; > + > + if (connected && !online) { > + log_info("No network connectivity, watching for changes."); > + manager_disconnect(m); > + > + } else if (!connected && online) { > + log_info("Network configuration changed, trying to establish > connection."); > + > + r = manager_connect(m); > + if (r < 0) > + return r; > + } > + > + return 0; > +} > + > +static int manager_network_monitor_listen(Manager *m) { > + int r, fd, events; > + > + assert(m); > + > + r = sd_network_monitor_new(&m->network_monitor, NULL); > + if (r < 0) > + return r; > + > + fd = sd_network_monitor_get_fd(m->network_monitor); > + if (fd < 0) > + return fd; > + > + events = sd_network_monitor_get_events(m->network_monitor); > + if (events < 0) > + return events; > + > + r = sd_event_add_io(m->event, &m->network_event_source, fd, events, > manager_network_event_handler, m); > + if (r < 0) > + return r; > + > + return 0; > +} > + > +void manager_free(Manager *m) { > + if (!m) > + return; > + > + manager_disconnect(m); > + > + free(m->last_cursor); > + free(m->current_cursor); > + > + free(m->state_file); > + > + sd_event_source_unref(m->network_event_source); > + sd_network_monitor_unref(m->network_monitor); > + > + sd_event_source_unref(m->sigterm_event); > + sd_event_source_unref(m->sigint_event); > + > + sd_event_unref(m->event); > + > + free(m); > +} > + > +int manager_new(Manager **ret, const char *state_file, const char *cursor) { > + _cleanup_(manager_freep) Manager *m = NULL; > + int r; > + > + assert(ret); > + > + m = new0(Manager, 1); > + if (!m) > + return -ENOMEM; > + > + m->socket = m->journal_watch_fd = -1; > + > + m->state_file = strdup(state_file); > + if (!m->state_file) > + return -ENOMEM; > + > + if (cursor) { > + m->last_cursor = strdup(cursor); > + if (!m->last_cursor) > + return -ENOMEM; > + } > + > + r = sd_event_default(&m->event); > + if (r < 0) > + return log_error_errno(r, "sd_event_default failed: %m"); > + > + assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0); > + > + r = sd_event_add_signal(m->event, NULL, SIGTERM, > manager_signal_event_handler, m); > + if (r < 0) > + return r; > + > + r = sd_event_add_signal(m->event, NULL, SIGINT, > manager_signal_event_handler, m); > + if (r < 0) > + return r; > + > + sd_event_set_watchdog(m->event, true); > + > + r = manager_network_monitor_listen(m); > + if (r < 0) > + return r; > + > + *ret = m; > + m = NULL; > + > + return 0; > +} > diff --git a/src/journal-remote/journal-syslog-manager.h > b/src/journal-remote/journal-syslog-manager.h > new file mode 100644 > index 0000000..aeb553b > --- /dev/null > +++ b/src/journal-remote/journal-syslog-manager.h > @@ -0,0 +1,70 @@ > +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ > + > +/*** > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +***/ > + > +#pragma once > + > +#include "sd-event.h" > +#include "sd-network.h" > +#include "socket-util.h" > +#include "sd-journal.h" > + > +typedef struct Manager Manager; > + > +struct Manager { > + sd_event *event; > + sd_event_source *event_journal_input; > + uint64_t timeout; > + > + sd_event_source *sigint_event, *sigterm_event; > + > + /* network */ > + sd_event_source *network_event_source; > + sd_network_monitor *network_monitor; > + > + int socket; > + > + /* Multicast UDP address */ > + SocketAddress address; > + > + /* journal */ > + int journal_watch_fd; > + sd_journal *journal; > + > + char *state_file; > + > + char *last_cursor, *current_cursor; > +}; > + > +int manager_new(Manager **ret, const char *state_file, const char *cursor); > +void manager_free(Manager *m); > + > +DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); > + > +int manager_connect(Manager *m); > +void manager_disconnect(Manager *m); > + > +void manager_close_network_socket(Manager *m); > +int manager_open_network_socket(Manager *m); > + > +int manager_push_to_network(Manager *m, int severity, int facility, > + const char *identifier, const char *message, > + const char *hostname, const char *pid, > + const struct timeval *tv); > diff --git a/src/journal-remote/journal-syslog-network.c > b/src/journal-remote/journal-syslog-network.c > new file mode 100644 > index 0000000..26ac362 > --- /dev/null > +++ b/src/journal-remote/journal-syslog-network.c > @@ -0,0 +1,201 @@ > +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ > + > +/*** > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +***/ > + > +#include <unistd.h> > +#include <stddef.h> > +#include <poll.h> > + > +#include "journal-syslog-manager.h" > + > +#define RFC_5424_NILVALUE "-" > +#define RFC_5424_PROTOCOL 1 > + > +#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC) > + > +static int sendmsg_loop(Manager *m, struct msghdr *mh) { > + int r; > + > + assert(m); > + assert(mh); > + > + for (;;) { > + if (sendmsg(m->socket, mh, MSG_NOSIGNAL) >= 0) > + return 0; > + > + if (errno == EINTR) > + continue; > + > + if (errno != EAGAIN) > + return -errno; > + > + r = fd_wait_for_event(m->socket, POLLOUT, SEND_TIMEOUT_USEC); > + if (r < 0) > + return r; > + if (r == 0) > + return -ETIMEDOUT; > + } > + > + return 0; > +} > + > +static int network_send(Manager *m, struct iovec *iovec, unsigned n_iovec) { > + struct msghdr mh = { > + .msg_iov = iovec, > + .msg_iovlen = n_iovec, > + }; > + > + assert(m); > + assert(iovec); > + assert(n_iovec > 0); > + > + if (m->address.sockaddr.sa.sa_family == AF_INET) { > + mh.msg_name = &m->address.sockaddr.sa; > + mh.msg_namelen = sizeof(m->address.sockaddr.sa); > + } else if (m->address.sockaddr.sa.sa_family == AF_INET6) { > + mh.msg_name = &m->address.sockaddr.in6; > + mh.msg_namelen = sizeof(m->address.sockaddr.in6); > + } else > + return -EAFNOSUPPORT; > + > + return sendmsg_loop(m, &mh); > +} > + > +/* rfc3339 timestamp format: yyyy-mm-ddthh:mm:ss[.frac]<+/->zz:zz */ > +static void format_rfc3339_timestamp(const struct timeval *tv, char > *header_time, size_t header_size) { > + char gm_buf[sizeof("+0530") + 1]; > + struct tm tm; > + time_t t; > + > + assert(header_time); > + > + t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / > USEC_PER_SEC)); > + localtime_r(&t, &tm); > + > + strftime(header_time, header_size, "%Y-%m-%dT%T", &tm); > + > + /* add fractional part */ > + if (tv) > + snprintf(header_time + strlen(header_time), header_size, > ".%06ld", tv->tv_usec); > + > + /* format the timezone according to RFC */ > + xstrftime(gm_buf, "%z", &tm); > + snprintf(header_time + strlen(header_time), header_size, "%.3s:%.2s > ", gm_buf, gm_buf + 3); > +} > + > +/* The Syslog Protocol RFC5424 format : > + * <pri>version sp timestamp sp hostname sp app-name sp procid sp msgid sp > [sd-id]s sp msg > + */ > +int manager_push_to_network(Manager *m, > + int severity, > + int facility, > + const char *identifier, > + const char *message, > + const char *hostname, > + const char *pid, > + const struct timeval *tv) { > + char header_priority[sizeof("< >1 ") + 1]; > + char header_time[FORMAT_TIMESTAMP_MAX]; > + uint16_t makepri; > + struct iovec iov[13]; > + int n = 0; > + > + assert(m); > + assert(message); > + > + makepri = (facility << 3) + severity; > + /* First: priority field Second: Version '<pri>version' */ > + snprintf(header_priority, sizeof(header_priority), "<%i>%i ", > makepri, RFC_5424_PROTOCOL); > + IOVEC_SET_STRING(iov[n++], header_priority); > + > + /* Third: timestamp */ > + format_rfc3339_timestamp(tv, header_time, sizeof(header_time)); > + IOVEC_SET_STRING(iov[n++], header_time); > + > + /* Fourth: hostname */ > + if (hostname) > + IOVEC_SET_STRING(iov[n++], hostname); > + else > + IOVEC_SET_STRING(iov[n++], RFC_5424_NILVALUE); > + > + IOVEC_SET_STRING(iov[n++], " "); > + > + /* Fifth: identifier */ > + if (identifier) > + IOVEC_SET_STRING(iov[n++], identifier); > + else > + IOVEC_SET_STRING(iov[n++], RFC_5424_NILVALUE); > + > + IOVEC_SET_STRING(iov[n++], " "); > + > + /* Sixth: procid */ > + if (pid) > + IOVEC_SET_STRING(iov[n++], pid); > + else > + IOVEC_SET_STRING(iov[n++], RFC_5424_NILVALUE); > + > + IOVEC_SET_STRING(iov[n++], " "); > + > + /* Seventh: msgid */ > + IOVEC_SET_STRING(iov[n++], RFC_5424_NILVALUE); > + IOVEC_SET_STRING(iov[n++], " "); > + > + /* Eighth: [structured-data] */ > + IOVEC_SET_STRING(iov[n++], RFC_5424_NILVALUE); > + IOVEC_SET_STRING(iov[n++], " "); > + > + /* Ninth: message */ > + IOVEC_SET_STRING(iov[n++], message); > + > + return network_send(m, iov, n); > +} > + > +void manager_close_network_socket(Manager *m) { > + assert(m); > + > + m->socket = safe_close(m->socket); > +} > + > +int manager_open_network_socket(Manager *m) { > + const int one = 1; > + int r; > + > + assert(m); > + > + if (!IN_SET(m->address.sockaddr.sa.sa_family, AF_INET, AF_INET6)) > + return -EAFNOSUPPORT; > + > + m->socket = socket(m->address.sockaddr.sa.sa_family, > SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); > + if (m->socket < 0) > + return -errno; > + > + r = setsockopt(m->socket, IPPROTO_IP, IP_MULTICAST_LOOP, &one, > sizeof(one)); > + if (r < 0) { > + r = -errno; > + goto fail; > + } > + > + return m->socket; > + > + fail: > + m->socket = safe_close(m->socket); > + return r; > +} > diff --git a/src/journal-remote/journal-syslogd.c > b/src/journal-remote/journal-syslogd.c > new file mode 100644 > index 0000000..fd8e770 > --- /dev/null > +++ b/src/journal-remote/journal-syslogd.c > @@ -0,0 +1,217 @@ > +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ > + > +/*** > + This file is part of systemd. > + > + Copyright 2015 Susant Sahani > + > + systemd is free software; you can redistribute it and/or modify it > + under the terms of the GNU Lesser General Public License as published by > + the Free Software Foundation; either version 2.1 of the License, or > + (at your option) any later version. > + > + systemd is distributed in the hope that it will be useful, but > + WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public License > + along with systemd; If not, see <http://www.gnu.org/licenses/>. > +***/ > + > +#include <stdio.h> > +#include <sys/stat.h> > +#include <fcntl.h> > +#include <getopt.h> > + > +#include "sd-daemon.h" > +#include "util.h" > +#include "build.h" > +#include "mkdir.h" > +#include "capability.h" > +#include "network-util.h" > +#include "journal-syslog-conf.h" > +#include "journal-syslog-manager.h" > + > +#define STATE_FILE "/var/lib/systemd/journal-syslogd/state" > + > +static const char *arg_cursor = NULL; > +static const char *arg_save_state = STATE_FILE; > + > +static int setup_cursor_state_file(Manager *m, uid_t uid, gid_t gid) { > + _cleanup_close_ int fd = -1; > + int r; > + > + assert(m); > + > + r = mkdir_parents(m->state_file, 0755); > + if (r < 0) > + return log_error_errno(r, "Cannot create parent directory of > state file %s: %m", > + m->state_file); > + > + fd = open(m->state_file, O_RDWR|O_CLOEXEC, 0644); > + if (fd >= 0) { > + > + /* Try to fix the access mode, so that we can still > + touch the file after dropping priviliges */ > + fchmod(fd, 0644); > + fchown(fd, uid, gid); > + } else > + /* create stamp file with the compiled-in date */ > + return touch_file(m->state_file, true, USEC_INFINITY, uid, > gid, 0644); > + > + return 0; > +} > + > +static void help(void) { > + printf("%s ..\n\n" > + "Send journal events to a UDP multicast group in RFC 5424 > syslog format.\n\n" > + " -h --help Show this help\n" > + " --version Show package version\n" > + " --cursor=CURSOR Start at the specified cursor\n" > + " --save-state[=FILE] Save uploaded cursors (default > \n" > + " " STATE_FILE ")\n" > + " -h --help Show this help and exit\n" > + " --version Print version string and exit\n" > + , program_invocation_short_name); > +} > + > +static int parse_argv(int argc, char *argv[]) { > + enum { > + ARG_VERSION = 0x100, > + ARG_CURSOR, > + ARG_SAVE_STATE, > + }; > + > + static const struct option options[] = { > + { "help", no_argument, NULL, 'h' > }, > + { "version", no_argument, NULL, ARG_VERSION > }, > + { "cursor", required_argument, NULL, ARG_CURSOR > }, > + { "save-state", optional_argument, NULL, ARG_SAVE_STATE > }, > + {} > + }; > + > + int c; > + > + assert(argc >= 0); > + assert(argv); > + > + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) > + switch(c) { > + case 'h': > + help(); > + return 0 /* done */; > + > + case ARG_VERSION: > + puts(PACKAGE_STRING); > + puts(SYSTEMD_FEATURES); > + return 0 /* done */; > + case ARG_CURSOR: > + if (arg_cursor) { > + log_error("cannot use more than one > --cursor/--after-cursor"); > + return -EINVAL; > + } > + > + arg_cursor = optarg; > + break; > + case ARG_SAVE_STATE: > + arg_save_state = optarg ?: STATE_FILE; > + break; > + > + case '?': > + log_error("Unknown option %s.", argv[optind-1]); > + return -EINVAL; > + > + case ':': > + log_error("Missing argument to %s.", argv[optind-1]); > + return -EINVAL; > + > + default: > + assert_not_reached("Unhandled option code."); > + } > + > + > + if (optind < argc) { > + log_error("Input arguments make no sense with journal > input."); > + return -EINVAL; > + } > + > + return 1; > +} > + > +int main(int argc, char **argv) { > + _cleanup_(manager_freep) Manager *m = NULL; > + const char *user = "systemd-journal-syslog"; > + uid_t uid; > + gid_t gid; > + int r; > + > + log_show_color(true); > + log_set_target(LOG_TARGET_AUTO); > + log_parse_environment(); > + log_open(); > + > + umask(0022); > + > + r = get_user_creds(&user, &uid, &gid, NULL, NULL); > + if (r < 0) { > + log_error_errno(r, "Cannot resolve user name %s: %m", user); > + goto finish; > + } > + > + r = parse_argv(argc, argv); > + if (r <= 0) > + goto finish; THis shoudl be moved up, so --help works regardless of the user being created. > + > + r = manager_new(&m, arg_save_state, arg_cursor); > + if (r < 0) { > + log_error_errno(r, "Failed to allocate manager: %m"); > + goto finish; > + } > + > + r = manager_parse_config_file(m); > + if (r < 0) { > + log_error_errno(r, "Failed to parse configuration file: %m"); > + goto finish; > + } > + > + r = setup_cursor_state_file(m, uid, gid); > + if (r < 0) > + goto cleanup; > + > + r = drop_privileges(uid, gid, > + (1ULL << CAP_NET_ADMIN) | > + (1ULL << CAP_NET_BIND_SERVICE) | > + (1ULL << CAP_NET_BROADCAST)); > + if (r < 0) > + goto finish; > + > + log_debug("%s running as pid "PID_FMT, > + program_invocation_short_name, getpid()); > + > + sd_notify(false, > + "READY=1\n" > + "STATUS=Processing input..."); > + > + if (network_is_online()) { > + r = manager_connect(m); > + if (r < 0) > + goto finish; > + } > + > + r = sd_event_loop(m->event); > + if (r < 0) { > + log_error_errno(r, "Failed to run event loop: %m"); > + goto finish; > + } > + > + sd_event_get_exit_code(m->event, &r); > + > + cleanup: > + sd_notify(false, > + "STOPPING=1\n" > + "STATUS=Shutting down..."); > + > + finish: > + return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; > +} > diff --git a/src/journal-remote/journal-syslogd.conf.in > b/src/journal-remote/journal-syslogd.conf.in > new file mode 100644 > index 0000000..b567a46 > --- /dev/null > +++ b/src/journal-remote/journal-syslogd.conf.in > @@ -0,0 +1,2 @@ > +[Network] > +#Address=239.0.0.1:6000 > diff --git a/units/systemd-journal-syslogd.service > b/units/systemd-journal-syslogd.service > new file mode 100644 > index 0000000..6e8bfc5 > --- /dev/null > +++ b/units/systemd-journal-syslogd.service > @@ -0,0 +1,18 @@ > +# This file is part of systemd. > +# > +# systemd is free software; you can redistribute it and/or modify it > +# under the terms of the GNU Lesser General Public License as published by > +# the Free Software Foundation; either version 2.1 of the License, or > +# (at your option) any later version. > +[Unit] > +Description=Journal Syslog Unicast and Multicast Daemon > +After=network.target > + > +[Service] > +ExecStart=/usr/lib/systemd/systemd-journal-syslogd > +PrivateTmp=yes > +PrivateDevices=yes > +WatchdogSec=20min > + > +[Install] > +WantedBy=multi-user.target Looks nice, but still some polish is required. Zbyszek _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel