[systemd-devel] [PATCH] journal: Introduce journal-netlogd

Susant Sahani susant at redhat.com
Mon Apr 20 02:03:51 PDT 2015


   This tiny daemon forwards messages from the journal to other
   hosts over the network using the traditional syslog format RFC 5424.
   It can be configured to send messages to both unicast and multicast addresses.
   systemd-journal-netlogd runs with own user systemd-journal-netlog.
   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

V4:
	1. fix mh.msg_name = &m->address.sockaddr.sa and
	     mh.msg_namelen = sizeof(m->address.sockaddr.sa
	2. rename binary to systemd-journal-netlogd
	3. Fix man and created two for binary and conf
	4. manager_read_journal_input: removed n as it's not used
	5. update_cursor_state fixed free
	6. "Not available" → "not available".
	7. parse_argv(argc, argv);
	   moved up, so --help works regardless of the user being created.
---
 Makefile-man.am                               |  10 +
 Makefile.am                                   |  37 ++
 man/journal-netlogd.conf.xml                  | 115 ++++++
 man/systemd-journal-netlogd.xml               | 123 +++++++
 src/journal-remote/journal-netlog-conf.c      |  61 ++++
 src/journal-remote/journal-netlog-conf.h      |  39 ++
 src/journal-remote/journal-netlog-gperf.gperf |  18 +
 src/journal-remote/journal-netlog-manager.c   | 498 ++++++++++++++++++++++++++
 src/journal-remote/journal-netlog-manager.h   |  70 ++++
 src/journal-remote/journal-netlog-network.c   | 201 +++++++++++
 src/journal-remote/journal-netlogd.c          | 234 ++++++++++++
 src/journal-remote/journal-netlogd.conf.in    |   2 +
 units/systemd-journal-netlogd.service         |  18 +
 13 files changed, 1426 insertions(+)
 create mode 100644 man/journal-netlogd.conf.xml
 create mode 100644 man/systemd-journal-netlogd.xml
 create mode 100644 src/journal-remote/journal-netlog-conf.c
 create mode 100644 src/journal-remote/journal-netlog-conf.h
 create mode 100644 src/journal-remote/journal-netlog-gperf.gperf
 create mode 100644 src/journal-remote/journal-netlog-manager.c
 create mode 100644 src/journal-remote/journal-netlog-manager.h
 create mode 100644 src/journal-remote/journal-netlog-network.c
 create mode 100644 src/journal-remote/journal-netlogd.c
 create mode 100644 src/journal-remote/journal-netlogd.conf.in
 create mode 100644 units/systemd-journal-netlogd.service

diff --git a/Makefile-man.am b/Makefile-man.am
index 2f3e5f2..401ea8d 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -1380,6 +1380,16 @@ man/systemd-journal-gatewayd.socket.html: man/systemd-journal-gatewayd.service.h
 
 endif
 
+MANPAGES += \
+        man/journal-netlogd.conf.5 \
+        man/systemd-journal-netlogd.8
+MANPAGES_ALIAS += \
+         man/journal-netlogd.conf.d.5 \
+         man/systemd-journal-netlogd.8
+man/systemd-journal-netlogd.5: man/systemd-journal-netlogd.conf.5
+man/journal-netlogd.conf.d.html: man/journal-netlogd.conf.html
+        $(html-alias)
+
 if HAVE_MYHOSTNAME
 MANPAGES += \
 	man/nss-myhostname.8
diff --git a/Makefile.am b/Makefile.am
index 68d8252..ca86c26 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4397,6 +4397,43 @@ EXTRA_DIST += \
 	src/journal-remote/journal-upload.conf.in
 endif
 
+systemd_journal_netlogd_SOURCES = \
+	src/journal-remote/journal-netlog-manager.h \
+	src/journal-remote/journal-netlog-manager.c \
+	src/journal-remote/journal-netlog-conf.h \
+	src/journal-remote/journal-netlog-conf.c \
+	src/journal-remote/journal-netlog-network.c \
+	src/journal-remote/journal-netlogd.c
+
+nodist_systemd_journal_netlogd_SOURCES = \
+	src/journal-remote/journal-netlog-gperf.c
+
+EXTRA_DIST += \
+        src/journal-remote/journal-netlog-gperf.gperf
+
+CLEANFILES += \
+        src/journal-remote/journal-netlog-gperf.c
+
+systemd_journal_netlogd_LDADD = \
+	libsystemd-internal.la \
+	libsystemd-journal-internal.la \
+	libsystemd-shared.la
+
+rootlibexec_PROGRAMS += \
+	systemd-journal-netlogd
+
+nodist_systemunit_DATA += \
+	units/systemd-journal-netlogd.service
+
+EXTRA_DIST += \
+	units/systemd-journal-netlogd.service.in
+
+nodist_pkgsysconf_DATA += \
+	src/journal-remote/journal-netlogd.conf
+
+EXTRA_DIST += \
+	src/journal-remote/journal-netlogd.conf.in
+
 # using _CFLAGS = in the conditional below would suppress AM_CFLAGS
 journalctl_CFLAGS = \
 	$(AM_CFLAGS)
diff --git a/man/journal-netlogd.conf.xml b/man/journal-netlogd.conf.xml
new file mode 100644
index 0000000..186178c
--- /dev/null
+++ b/man/journal-netlogd.conf.xml
@@ -0,0 +1,115 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!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="journal-netlogd.conf" xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>journal-netlogd.conf</title>
+    <productname>systemd</productname>
+
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>Susant</firstname>
+        <surname>Sahani</surname>
+        <email>ssahani at gmail.com</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>journal-netlogd.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>journal-netlogd.conf</refname>
+    <refname>journal-netlogd.conf.d</refname>
+    <refpurpose>Journal netlogd service configuration files</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <para><filename>/etc/systemd/journal-netlogd.conf</filename></para>
+    <para><filename>/etc/systemd/journald.conf.d/*.conf</filename></para>
+    <para><filename>/run/systemd/journald.conf.d/*.conf</filename></para>
+    <para><filename>/usr/lib/systemd/journald.conf.d/*.conf</filename></para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>These files configure various parameters of the systemd-journal-netlogd
+    application,
+    <citerefentry><refentrytitle>systemd-journal-netlogd</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</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-netlogd.conf</title>
+      <programlisting>[Network]
+Address=239.0.0.1:6000
+      </programlisting>
+    </example>
+  </refsect1>
+
+    <refsect1>
+    <title>Example</title>
+    <example>
+      <title>/etc/systemd/journal-netlogd.conf</title>
+      <programlisting>[Network]
+Address=192.168.8.101:514
+      </programlisting>
+    </example>
+  </refsect1>
+
+  <refsect1>
+      <title>See Also</title>
+      <para>
+        <citerefentry><refentrytitle>systemd-journal-netlogd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      </para>
+  </refsect1>
+
+</refentry>
diff --git a/man/systemd-journal-netlogd.xml b/man/systemd-journal-netlogd.xml
new file mode 100644
index 0000000..f2e953b
--- /dev/null
+++ b/man/systemd-journal-netlogd.xml
@@ -0,0 +1,123 @@
+<?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-netlogd" xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>systemd-journal-netlogd</title>
+    <productname>systemd</productname>
+
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>Susant</firstname>
+        <surname>Sahani</surname>
+        <email>ssahani at gmail.com</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>systemd-journal-netlogd</refentrytitle>
+    <manvolnum>8</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>systemd-journal-netlogd</refname>
+    <refpurpose>Send journal messages over the network in syslog RFC 5424 format</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>systemd-journal-netlogd</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-netlogd</command> forwards messages from the
+      journal to other hosts over the network using the traditional syslog
+      format following <ulink url="https://tools.ietf.org/html/rfc5424">RFC 5424</ulink>.
+      It can be configured to send messages to both unicast and multicast addresses.
+    </para>
+  </refsect1>
+
+   <refsect1>
+    <para>The program is started by
+    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+    Use <command>systemctl start systemd-journal-netlogd.service</command> to start
+    the service, and <command>systemctl enable systemd-journal-netlogd.service</command>
+    to have it started on boot.</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-netlogd/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>See Also</title>
+    <para>
+      <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd</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>
+    </para>
+  </refsect1>
+ </refentry>
diff --git a/src/journal-remote/journal-netlog-conf.c b/src/journal-remote/journal-netlog-conf.c
new file mode 100644
index 0000000..5e3e10b
--- /dev/null
+++ b/src/journal-remote/journal-netlog-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-netlog-conf.h"
+
+int config_parse_netlog_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-netlogd.conf",
+                                 CONF_DIRS_NULSTR("systemd/journal-netlogd.conf"),
+                                 "Network\0",
+                                 config_item_perf_lookup, journal_netlog_gperf_lookup,
+                                 false, m);
+}
diff --git a/src/journal-remote/journal-netlog-conf.h b/src/journal-remote/journal-netlog-conf.h
new file mode 100644
index 0000000..20e20c1
--- /dev/null
+++ b/src/journal-remote/journal-netlog-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-netlog-manager.h"
+
+const struct ConfigPerfItem* journal_netlog_gperf_lookup(const char *key, unsigned length);
+int config_parse_netlog_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-netlog-gperf.gperf b/src/journal-remote/journal-netlog-gperf.gperf
new file mode 100644
index 0000000..c0708d5
--- /dev/null
+++ b/src/journal-remote/journal-netlog-gperf.gperf
@@ -0,0 +1,18 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "journal-netlog-conf.h"
+#include "journal-netlog-manager.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name journal_netlog_gperf_hash
+%define lookup-function-name journal_netlog_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+Network.Address,  config_parse_netlog_broadcast_address, 0, 0
diff --git a/src/journal-remote/journal-netlog-manager.c b/src/journal-remote/journal-netlog-manager.c
new file mode 100644
index 0000000..ca1eff4
--- /dev/null
+++ b/src/journal-remote/journal-netlog-manager.c
@@ -0,0 +1,498 @@
+/*-*- 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-netlog-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 fl, nl;
+        void *buf;
+
+        assert(data);
+        assert(field);
+        assert(target);
+
+        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;
+
+        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;
+        unsigned sev = JOURNAL_DEFAULT_SEVERITY;
+        unsigned fac = JOURNAL_DEFAULT_FACILITY;
+        struct timeval tv;
+        usec_t realtime;
+        const void *data;
+        size_t length;
+        int r;
+
+        assert(m);
+        assert(m->journal);
+
+        JOURNAL_FOREACH_DATA_RETVAL(m->journal, data, length, r) {
+
+                r = parse_field(data, length, "PRIORITY=", &priority);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "SYSLOG_FACILITY=", &facility);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_HOSTNAME=", &hostname);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "_PID=", &pid);
+                if (r < 0)
+                        return r;
+                else if (r > 0)
+                        continue;
+
+                r = parse_field(data, length, "MESSAGE=", &message);
+                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_atou(facility, &fac);
+                if (r < 0)
+                        log_debug("Failed to parse syslog facility: %s", facility);
+
+                if (fac >= LOG_NFACILITIES)
+                        fac = JOURNAL_DEFAULT_FACILITY;
+        }
+
+        if (priority) {
+                r = safe_atou(priority, &sev);
+                if (r < 0)
+                        log_debug("Failed to parse syslog priority: %s", priority);
+
+                if (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;
+        }
+
+ finish:
+        if (r < 0)
+                log_error_errno(r, "Failed to save state %s: %m", m->state_file);
+
+        if (temp_path)
+                (void) unlink(temp_path);
+
+        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");
+
+        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, 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-netlog-manager.h b/src/journal-remote/journal-netlog-manager.h
new file mode 100644
index 0000000..aeb553b
--- /dev/null
+++ b/src/journal-remote/journal-netlog-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-netlog-network.c b/src/journal-remote/journal-netlog-network.c
new file mode 100644
index 0000000..355aa94
--- /dev/null
+++ b/src/journal-remote/journal-netlog-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-netlog-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.in);
+        } else if (m->address.sockaddr.sa.sa_family == AF_INET6) {
+                mh.msg_name = &m->address.sockaddr.sa;
+                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-netlogd.c b/src/journal-remote/journal-netlogd.c
new file mode 100644
index 0000000..93ac7dc
--- /dev/null
+++ b/src/journal-remote/journal-netlogd.c
@@ -0,0 +1,234 @@
+/*-*- 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 "path-util.h"
+#include "capability.h"
+#include "network-util.h"
+#include "journal-netlog-conf.h"
+#include "journal-netlog-manager.h"
+
+#define STATE_FILE "/var/lib/systemd/journal-netlogd/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_free_ char *dir = NULL;
+        _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);
+
+        r =  path_get_parent(m->state_file, &dir);
+        if ( r < 0)
+                return log_error_errno(r,
+                                       "Failed to find parent directory of state file %s: %m",
+                                       m->state_file);
+
+        /* change permission of the state file parent dir */
+        r = chmod_and_chown(dir, 0744, uid, gid);
+        if (r < 0)
+                return log_error_errno(r,
+                                       "Failed to change permission 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"
+               "Forwards messages from the journal to other hosts over the network using the syslog\n"
+               "RFC 5424 format in both unicast and multicast addresses.\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-netlog";
+        uid_t uid;
+        gid_t gid;
+        int r;
+
+        log_show_color(true);
+        log_set_target(LOG_TARGET_AUTO);
+        log_parse_environment();
+        log_open();
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                goto finish;
+
+        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 = 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-netlogd.conf.in b/src/journal-remote/journal-netlogd.conf.in
new file mode 100644
index 0000000..b567a46
--- /dev/null
+++ b/src/journal-remote/journal-netlogd.conf.in
@@ -0,0 +1,2 @@
+[Network]
+#Address=239.0.0.1:6000
diff --git a/units/systemd-journal-netlogd.service b/units/systemd-journal-netlogd.service
new file mode 100644
index 0000000..0cec509
--- /dev/null
+++ b/units/systemd-journal-netlogd.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-netlogd
+PrivateTmp=yes
+PrivateDevices=yes
+WatchdogSec=20min
+
+[Install]
+WantedBy=multi-user.target
-- 
2.3.5



More information about the systemd-devel mailing list