summaryrefslogtreecommitdiffstats
path: root/meta-networking/recipes-protocols/net-snmp/net-snmp
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2013-04-22 08:45:45 +0000
committerMartin Jansa <Martin.Jansa@gmail.com>2013-04-26 10:00:32 +0200
commit9e7327e446d16a8bd70f93d5d68cdf267e3d2106 (patch)
treec7b80ce3e0389f561ca0ac18accd544a34d2c28f /meta-networking/recipes-protocols/net-snmp/net-snmp
parent9d68ba4fc2b2f862bfb9619f74e082c88ab68604 (diff)
downloadmeta-openembedded-9e7327e446d16a8bd70f93d5d68cdf267e3d2106.tar.gz
net-snmp: move to meta-networking and tweak
* Set SUMMARY instead of DESCRIPTION * Move SRC_URI checksums under SRC_URI * Move packaging definitions to the end Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
Diffstat (limited to 'meta-networking/recipes-protocols/net-snmp/net-snmp')
-rw-r--r--meta-networking/recipes-protocols/net-snmp/net-snmp/snmpd.service13
-rw-r--r--meta-networking/recipes-protocols/net-snmp/net-snmp/snmptrapd.service13
-rw-r--r--meta-networking/recipes-protocols/net-snmp/net-snmp/systemd-support.patch1616
3 files changed, 1642 insertions, 0 deletions
diff --git a/meta-networking/recipes-protocols/net-snmp/net-snmp/snmpd.service b/meta-networking/recipes-protocols/net-snmp/net-snmp/snmpd.service
new file mode 100644
index 000000000..10a1eb212
--- /dev/null
+++ b/meta-networking/recipes-protocols/net-snmp/net-snmp/snmpd.service
@@ -0,0 +1,13 @@
1[Unit]
2Description=Simple Network Management Protocol (SNMP) Daemon.
3After=syslog.target network.target
4
5[Service]
6Type=notify
7Environment=OPTIONS="-LS0-6d"
8EnvironmentFile=-/etc/default/snmpd
9ExecStart=/usr/sbin/snmpd $OPTIONS -f
10ExecReload=/bin/kill -HUP $MAINPID
11
12[Install]
13WantedBy=multi-user.target
diff --git a/meta-networking/recipes-protocols/net-snmp/net-snmp/snmptrapd.service b/meta-networking/recipes-protocols/net-snmp/net-snmp/snmptrapd.service
new file mode 100644
index 000000000..951f9f270
--- /dev/null
+++ b/meta-networking/recipes-protocols/net-snmp/net-snmp/snmptrapd.service
@@ -0,0 +1,13 @@
1[Unit]
2Description=Simple Network Management Protocol (SNMP) Trap Daemon.
3After=syslog.target network.target
4
5[Service]
6Type=notify
7Environment=OPTIONS="-Lsd"
8EnvironmentFile=-/etc/default/snmptrapd
9ExecStart=/usr/sbin/snmptrapd $OPTIONS -f
10ExecReload=/bin/kill -HUP $MAINPID
11
12[Install]
13WantedBy=multi-user.target
diff --git a/meta-networking/recipes-protocols/net-snmp/net-snmp/systemd-support.patch b/meta-networking/recipes-protocols/net-snmp/net-snmp/systemd-support.patch
new file mode 100644
index 000000000..18955f29e
--- /dev/null
+++ b/meta-networking/recipes-protocols/net-snmp/net-snmp/systemd-support.patch
@@ -0,0 +1,1616 @@
1Systemd support backported from the master branch as of 23/04/2012 (post 5.7.1, pre 5.8).
2
3The following commits have been cherry-picked:
4
519499c3c90bf9d7b2b9e5d08baa26cc6bba28a11
6fef6cddfdb94da1a6b1fb768af62918b80f11fd3
70641e43c694c485cbbffef0556efc4641bd3ff50
876530a89f1c8bbd0b63acce63e10d5d4812a1a16 (conflict resolved)
9bf108d7f1354f6276fc43c129963f2c49b9fc242
1074412748067c685e1d8ab6ed3bcc3ca9c2774844
1186132e3f1e6ef7b4e0b96d8fa24e37c81b71b0e0
1263557cf8986a33dba1d4429b583a901361052c4f
13
14Upstream-Status: Backport
15
16diff --git a/README.systemd b/README.systemd
17new file mode 100644
18index 0000000..f731851
19--- /dev/null
20+++ b/README.systemd
21@@ -0,0 +1,41 @@
22+README.systemd
23+--------------
24+Net-SNMP provides two daemons, which support systemd system manager.
25+See http://www.freedesktop.org/wiki/Software/systemd to learn how
26+systemd works. Both socket activation and notification is supported by these
27+daemons.
28+
29+To enable systemd support, the sources must be compiled with
30+--with-systemd configure option.
31+
32+snmpd - The SNMP agent
33+----------------------
34+Socket activation od snmpd daemon is implemented, but it's discouraged.
35+The reason is simple - snmpd not only listens and processes SNMP requests
36+from network, but also gathers system statistics counters, sends traps and
37+communicates with subagents. It even opens few netlink sockets.
38+
39+In other words, snmpd should run from system start to properly work.
40+This can be done in two ways:
41+1) either as snmpd service unit with 'Type=notification' and without a socket
42+ unit
43+2) or as snmpd service unit with 'Type=simple', appropriate socket socket unit
44+ and the snmpd service enabled. This way systemd creates the snmpd listening
45+ socket early during boot and passes the sockets to snmpd slightly later
46+ (but still during machine boot). This way systemd can paralelize start of
47+ services, which depend on snmpd. Admins must adjust the socket file manually,
48+ depending if the snmpd support AgentX, IPv6, SMUX etc.
49+
50+snmpd should be started with '-f' command line parameter to disable forking -
51+systemd does that for us automatically.
52+
53+
54+snmptrapd - The trap processing daemon
55+--------------------------------------
56+snmptrapd supports full socket activation and also notification (if needed).
57+Both 'Type=simple' (with appropriate socket unit) and 'Type=notify' services
58+will work. Again, '-f' parameter should be provided on snmptrapd command line.
59+
60+If integration with SNMP agent using AgentX protocol is enabled, snmptrapd should
61+start during boot and not after first SNMP trap arrives. Same rules as for snmpd
62+applies then.
63\ No newline at end of file
64diff --git a/agent/snmpd.c b/agent/snmpd.c
65index b177d5b..08bdfc7 100644
66--- a/agent/snmpd.c
67+++ b/agent/snmpd.c
68@@ -164,6 +164,10 @@ typedef long fd_mask;
69
70 #endif
71
72+#ifndef NETSNMP_NO_SYSTEMD
73+#include <net-snmp/library/sd-daemon.h>
74+#endif
75+
76 netsnmp_feature_want(logging_file)
77 netsnmp_feature_want(logging_stdio)
78 netsnmp_feature_want(logging_syslog)
79@@ -441,18 +445,28 @@ main(int argc, char *argv[])
80 int agent_mode = -1;
81 char *pid_file = NULL;
82 char option_compatability[] = "-Le";
83+#ifndef WIN32
84+ int prepared_sockets = 0;
85+#endif
86 #if HAVE_GETPID
87 int fd;
88 FILE *PID;
89 #endif
90
91 #ifndef WIN32
92+#ifndef NETSNMP_NO_SYSYSTEMD
93+ /* check if systemd has sockets for us and don't close them */
94+ prepared_sockets = netsnmp_sd_listen_fds(0);
95+#endif /* NETSNMP_NO_SYSYSTEMD */
96+
97 /*
98 * close all non-standard file descriptors we may have
99 * inherited from the shell.
100 */
101- for (i = getdtablesize() - 1; i > 2; --i) {
102- (void) close(i);
103+ if (!prepared_sockets) {
104+ for (i = getdtablesize() - 1; i > 2; --i) {
105+ (void) close(i);
106+ }
107 }
108 #endif /* #WIN32 */
109
110@@ -1100,6 +1114,19 @@ main(int argc, char *argv[])
111 netsnmp_addrcache_initialise();
112
113 /*
114+ * Let systemd know we're up.
115+ */
116+#ifndef NETSNMP_NO_SYSTEMD
117+ netsnmp_sd_notify(1, "READY=1\n");
118+ if (prepared_sockets)
119+ /*
120+ * Clear the environment variable, we already processed all the sockets
121+ * by now.
122+ */
123+ netsnmp_sd_listen_fds(1);
124+#endif
125+
126+ /*
127 * Forever monitor the dest_port for incoming PDUs.
128 */
129 DEBUGMSGTL(("snmpd/main", "We're up. Starting to process data.\n"));
130diff --git a/apps/snmptrapd.c b/apps/snmptrapd.c
131index 1a52080..0857ae1 100644
132--- a/apps/snmptrapd.c
133+++ b/apps/snmptrapd.c
134@@ -125,6 +125,10 @@ SOFTWARE.
135
136 #include <net-snmp/net-snmp-features.h>
137
138+#ifndef NETSNMP_NO_SYSTEMD
139+#include <net-snmp/library/sd-daemon.h>
140+#endif
141+
142 #ifndef BSD4_3
143 #define BSD4_2
144 #endif
145@@ -655,15 +659,24 @@ main(int argc, char *argv[])
146 int agentx_subagent = 1;
147 #endif
148 netsnmp_trapd_handler *traph;
149+#ifndef WIN32
150+ int prepared_sockets = 0;
151+#endif
152
153
154 #ifndef WIN32
155+#ifndef NETSNMP_NO_SYSTEMD
156+ /* check if systemd has sockets for us and don't close them */
157+ prepared_sockets = netsnmp_sd_listen_fds(0);
158+#endif
159 /*
160 * close all non-standard file descriptors we may have
161 * inherited from the shell.
162 */
163- for (i = getdtablesize() - 1; i > 2; --i) {
164- (void) close(i);
165+ if (!prepared_sockets) {
166+ for (i = getdtablesize() - 1; i > 2; --i) {
167+ (void) close(i);
168+ }
169 }
170 #endif /* #WIN32 */
171
172@@ -1311,6 +1324,19 @@ main(int argc, char *argv[])
173 #endif
174 #endif
175
176+ /*
177+ * Let systemd know we're up.
178+ */
179+#ifndef NETSNMP_NO_SYSTEMD
180+ netsnmp_sd_notify(1, "READY=1\n");
181+ if (prepared_sockets)
182+ /*
183+ * Clear the environment variable, we already processed all the sockets
184+ * by now.
185+ */
186+ netsnmp_sd_listen_fds(1);
187+#endif
188+
189 #ifdef WIN32SERVICE
190 trapd_status = SNMPTRAPD_RUNNING;
191 #endif
192diff --git a/configure.d/config_modules_lib b/configure.d/config_modules_lib
193index b6609c1..5849072 100644
194--- a/configure.d/config_modules_lib
195+++ b/configure.d/config_modules_lib
196@@ -53,6 +53,14 @@ if test "x$PARTIALTARGETOS" = "xmingw32" -o "x$PARTIALTARGETOS" = "xmingw32msvc"
197 other_ftobjs_list="$other_ftobjs_list winpipe.ft"
198 fi
199
200+# Linux systemd
201+if test "x$with_systemd" == "xyes"; then
202+ other_src_list="$other_src_list sd-daemon.c"
203+ other_objs_list="$other_objs_list sd-daemon.o"
204+ other_lobjs_list="$other_lobjs_list sd-daemon.lo"
205+ other_ftobjs_list="$other_ftobjs_list sd-daemon.ft"
206+fi
207+
208 AC_SUBST(other_src_list)
209 AC_SUBST(other_objs_list)
210 AC_SUBST(other_lobjs_list)
211diff --git a/configure.d/config_project_with_enable b/configure.d/config_project_with_enable
212index 8b46ad2..59d6d5c 100644
213--- a/configure.d/config_project_with_enable
214+++ b/configure.d/config_project_with_enable
215@@ -689,6 +689,15 @@ if test "x$with_dummy_values" != "xyes"; then
216 data for])
217 fi
218
219+NETSNMP_ARG_WITH(systemd,
220+[ --with-systemd Provide systemd support. See README.systemd
221+ for details.])
222+# Define unless specifically suppressed (i.e., option defaults to false).
223+if test "x$with_systemd" != "xyes"; then
224+ AC_DEFINE(NETSNMP_NO_SYSTEMD, 1,
225+ [If you don't want to integrate with systemd.])
226+fi
227+
228 NETSNMP_ARG_ENABLE(set-support,
229 [ --disable-set-support Do not allow SNMP set requests.])
230 if test "x$enable_set_support" = "xno"; then
231diff --git a/dist/snmpd.service b/dist/snmpd.service
232new file mode 100644
233index 0000000..31391e5
234--- /dev/null
235+++ b/dist/snmpd.service
236@@ -0,0 +1,18 @@
237+#
238+# SNMP agent service file for systemd
239+#
240+#
241+# The service should be enabled, i.e. snmpd should start during machine boot.
242+# Socket activation shall not be used. See README.systemd for details.
243+
244+[Unit]
245+Description=Simple Network Management Protocol (SNMP) daemon.
246+After=syslog.target network.target
247+
248+[Service]
249+# Type=notify is also supported. It should be set when snmpd.socket is not used.
250+Type=simple
251+ExecStart=/usr/sbin/snmpd -f
252+
253+[Install]
254+WantedBy=multi-user.target
255diff --git a/dist/snmpd.socket b/dist/snmpd.socket
256new file mode 100644
257index 0000000..7f3a2d9
258--- /dev/null
259+++ b/dist/snmpd.socket
260@@ -0,0 +1,17 @@
261+[Unit]
262+Description=Socket listening for SNMP and AgentX messages
263+
264+[Socket]
265+ListenDatagram=0.0.0.0:161
266+# Uncomment other listening addresses as needed - TCP, UDP6, TCP6.
267+# It must match listening addresses/ports defined in snmpd.service
268+# or snmpd.conf.
269+# ListenStream=0.0.0.0:161
270+# ListenDatagram=[::]:161
271+# ListenStream=[::]:161
272+#
273+# Uncomment AgentX socket if snmpd.conf enables AgentX protocol.
274+# ListenStream=/var/agentx/master
275+
276+[Install]
277+WantedBy=sockets.target
278diff --git a/dist/snmptrapd.service b/dist/snmptrapd.service
279new file mode 100644
280index 0000000..e88a5b4
281--- /dev/null
282+++ b/dist/snmptrapd.service
283@@ -0,0 +1,16 @@
284+#
285+# SNMP trap-processing service file for systemd
286+#
287+
288+[Unit]
289+Description=Simple Network Management Protocol (SNMP) Trap daemon.
290+After=syslog.target network.target
291+
292+[Service]
293+# Type=notify is also supported. It should be set when snmptrapd.socket is not
294+# used.
295+Type=simple
296+ExecStart=/usr/sbin/snmptrapd -f
297+
298+[Install]
299+WantedBy=multi-user.target
300diff --git a/dist/snmptrapd.socket b/dist/snmptrapd.socket
301new file mode 100644
302index 0000000..0fc8a7c
303--- /dev/null
304+++ b/dist/snmptrapd.socket
305@@ -0,0 +1,14 @@
306+[Unit]
307+Description=Socket listening for SNMP trap messages
308+
309+[Socket]
310+ListenDatagram=0.0.0.0:162
311+# Uncomment other listening addresses as needed - TCP, UDP6, TCP6.
312+# It must match listening addresses/ports defined in snmptrapd.service
313+# or snmptrapd.conf.
314+# ListenStream=0.0.0.0:162
315+# ListenDatagram=[::]:162
316+# ListenStream=[::]:162
317+
318+[Install]
319+WantedBy=sockets.target
320diff --git a/include/net-snmp/library/sd-daemon.h b/include/net-snmp/library/sd-daemon.h
321new file mode 100644
322index 0000000..85274c9
323--- /dev/null
324+++ b/include/net-snmp/library/sd-daemon.h
325@@ -0,0 +1,290 @@
326+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
327+
328+#ifndef SNMPD_SD_DAEMON_H
329+#define SNMPD_SD_DAEMON_H
330+
331+/***
332+ Copyright 2010 Lennart Poettering
333+
334+ Permission is hereby granted, free of charge, to any person
335+ obtaining a copy of this software and associated documentation files
336+ (the "Software"), to deal in the Software without restriction,
337+ including without limitation the rights to use, copy, modify, merge,
338+ publish, distribute, sublicense, and/or sell copies of the Software,
339+ and to permit persons to whom the Software is furnished to do so,
340+ subject to the following conditions:
341+
342+ The above copyright notice and this permission notice shall be
343+ included in all copies or substantial portions of the Software.
344+
345+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
346+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
347+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
348+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
349+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
350+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
351+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
352+ SOFTWARE.
353+***/
354+
355+#ifdef HAVE_SYS_TYPES_H
356+#include <sys/types.h>
357+#endif
358+#ifdef HAVE_INTTYPES_H
359+#include <inttypes.h>
360+#endif
361+
362+#ifdef __cplusplus
363+extern "C" {
364+#endif
365+
366+/*
367+ Reference implementation of a few systemd related interfaces for
368+ writing daemons. These interfaces are trivial to implement. To
369+ simplify porting we provide this reference implementation.
370+ Applications are welcome to reimplement the algorithms described
371+ here if they do not want to include these two source files.
372+
373+ The following functionality is provided:
374+
375+ - Support for logging with log levels on stderr
376+ - File descriptor passing for socket-based activation
377+ - Daemon startup and status notification
378+ - Detection of systemd boots
379+
380+ You may compile this with -DDISABLE_SYSTEMD to disable systemd
381+ support. This makes all those calls NOPs that are directly related to
382+ systemd (i.e. only sd_is_xxx() will stay useful).
383+
384+ Since this is drop-in code we don't want any of our symbols to be
385+ exported in any case. Hence we declare hidden visibility for all of
386+ them.
387+
388+ You may find an up-to-date version of these source files online:
389+
390+ http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h
391+ http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c
392+
393+ This should compile on non-Linux systems, too, but with the
394+ exception of the sd_is_xxx() calls all functions will become NOPs.
395+
396+ See sd-daemon(7) for more information.
397+*/
398+
399+#ifndef _sd_printf_attr_
400+#if __GNUC__ >= 4
401+#define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
402+#else
403+#define _sd_printf_attr_(a,b)
404+#endif
405+#endif
406+
407+/*
408+ Log levels for usage on stderr:
409+
410+ fprintf(stderr, SD_NOTICE "Hello World!\n");
411+
412+ This is similar to printk() usage in the kernel.
413+*/
414+#define SD_EMERG "<0>" /* system is unusable */
415+#define SD_ALERT "<1>" /* action must be taken immediately */
416+#define SD_CRIT "<2>" /* critical conditions */
417+#define SD_ERR "<3>" /* error conditions */
418+#define SD_WARNING "<4>" /* warning conditions */
419+#define SD_NOTICE "<5>" /* normal but significant condition */
420+#define SD_INFO "<6>" /* informational */
421+#define SD_DEBUG "<7>" /* debug-level messages */
422+
423+/* The first passed file descriptor is fd 3 */
424+#define SD_LISTEN_FDS_START 3
425+
426+/*
427+ Returns how many file descriptors have been passed, or a negative
428+ errno code on failure. Optionally, removes the $LISTEN_FDS and
429+ $LISTEN_PID file descriptors from the environment (recommended, but
430+ problematic in threaded environments). If r is the return value of
431+ this function you'll find the file descriptors passed as fds
432+ SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative
433+ errno style error code on failure. This function call ensures that
434+ the FD_CLOEXEC flag is set for the passed file descriptors, to make
435+ sure they are not passed on to child processes. If FD_CLOEXEC shall
436+ not be set, the caller needs to unset it after this call for all file
437+ descriptors that are used.
438+
439+ See sd_listen_fds(3) for more information.
440+*/
441+int netsnmp_sd_listen_fds(int unset_environment);
442+
443+/*
444+ Helper call for identifying a passed file descriptor. Returns 1 if
445+ the file descriptor is a FIFO in the file system stored under the
446+ specified path, 0 otherwise. If path is NULL a path name check will
447+ not be done and the call only verifies if the file descriptor
448+ refers to a FIFO. Returns a negative errno style error code on
449+ failure.
450+
451+ See sd_is_fifo(3) for more information.
452+*/
453+int netsnmp_sd_is_fifo(int fd, const char *path);
454+
455+/*
456+ Helper call for identifying a passed file descriptor. Returns 1 if
457+ the file descriptor is a special character device on the file
458+ system stored under the specified path, 0 otherwise.
459+ If path is NULL a path name check will not be done and the call
460+ only verifies if the file descriptor refers to a special character.
461+ Returns a negative errno style error code on failure.
462+
463+ See sd_is_special(3) for more information.
464+*/
465+int netsnmp_sd_is_special(int fd, const char *path);
466+
467+/*
468+ Helper call for identifying a passed file descriptor. Returns 1 if
469+ the file descriptor is a socket of the specified family (AF_INET,
470+ ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If
471+ family is 0 a socket family check will not be done. If type is 0 a
472+ socket type check will not be done and the call only verifies if
473+ the file descriptor refers to a socket. If listening is > 0 it is
474+ verified that the socket is in listening mode. (i.e. listen() has
475+ been called) If listening is == 0 it is verified that the socket is
476+ not in listening mode. If listening is < 0 no listening mode check
477+ is done. Returns a negative errno style error code on failure.
478+
479+ See sd_is_socket(3) for more information.
480+*/
481+int netsnmp_sd_is_socket(int fd, int family, int type, int listening);
482+
483+/*
484+ Helper call for identifying a passed file descriptor. Returns 1 if
485+ the file descriptor is an Internet socket, of the specified family
486+ (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM,
487+ SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version
488+ check is not done. If type is 0 a socket type check will not be
489+ done. If port is 0 a socket port check will not be done. The
490+ listening flag is used the same way as in sd_is_socket(). Returns a
491+ negative errno style error code on failure.
492+
493+ See sd_is_socket_inet(3) for more information.
494+*/
495+int netsnmp_sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port);
496+
497+/*
498+ Helper call for identifying a passed file descriptor. Returns 1 if
499+ the file descriptor is an AF_UNIX socket of the specified type
500+ (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0
501+ a socket type check will not be done. If path is NULL a socket path
502+ check will not be done. For normal AF_UNIX sockets set length to
503+ 0. For abstract namespace sockets set length to the length of the
504+ socket name (including the initial 0 byte), and pass the full
505+ socket path in path (including the initial 0 byte). The listening
506+ flag is used the same way as in sd_is_socket(). Returns a negative
507+ errno style error code on failure.
508+
509+ See sd_is_socket_unix(3) for more information.
510+*/
511+int netsnmp_sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length);
512+
513+/*
514+ Informs systemd about changed daemon state. This takes a number of
515+ newline separated environment-style variable assignments in a
516+ string. The following variables are known:
517+
518+ READY=1 Tells systemd that daemon startup is finished (only
519+ relevant for services of Type=notify). The passed
520+ argument is a boolean "1" or "0". Since there is
521+ little value in signaling non-readiness the only
522+ value daemons should send is "READY=1".
523+
524+ STATUS=... Passes a single-line status string back to systemd
525+ that describes the daemon state. This is free-from
526+ and can be used for various purposes: general state
527+ feedback, fsck-like programs could pass completion
528+ percentages and failing programs could pass a human
529+ readable error message. Example: "STATUS=Completed
530+ 66% of file system check..."
531+
532+ ERRNO=... If a daemon fails, the errno-style error code,
533+ formatted as string. Example: "ERRNO=2" for ENOENT.
534+
535+ BUSERROR=... If a daemon fails, the D-Bus error-style error
536+ code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut"
537+
538+ MAINPID=... The main pid of a daemon, in case systemd did not
539+ fork off the process itself. Example: "MAINPID=4711"
540+
541+ Daemons can choose to send additional variables. However, it is
542+ recommended to prefix variable names not listed above with X_.
543+
544+ Returns a negative errno-style error code on failure. Returns > 0
545+ if systemd could be notified, 0 if it couldn't possibly because
546+ systemd is not running.
547+
548+ Example: When a daemon finished starting up, it could issue this
549+ call to notify systemd about it:
550+
551+ sd_notify(0, "READY=1");
552+
553+ See sd_notifyf() for more complete examples.
554+
555+ See sd_notify(3) for more information.
556+*/
557+int netsnmp_sd_notify(int unset_environment, const char *state);
558+
559+/*
560+ Similar to sd_notify() but takes a format string.
561+
562+ Example 1: A daemon could send the following after initialization:
563+
564+ sd_notifyf(0, "READY=1\n"
565+ "STATUS=Processing requests...\n"
566+ "MAINPID=%lu",
567+ (unsigned long) getpid());
568+
569+ Example 2: A daemon could send the following shortly before
570+ exiting, on failure:
571+
572+ sd_notifyf(0, "STATUS=Failed to start up: %s\n"
573+ "ERRNO=%i",
574+ strerror(errno),
575+ errno);
576+
577+ See sd_notifyf(3) for more information.
578+*/
579+int netsnmp_sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3);
580+
581+/*
582+ Returns > 0 if the system was booted with systemd. Returns < 0 on
583+ error. Returns 0 if the system was not booted with systemd. Note
584+ that all of the functions above handle non-systemd boots just
585+ fine. You should NOT protect them with a call to this function. Also
586+ note that this function checks whether the system, not the user
587+ session is controlled by systemd. However the functions above work
588+ for both user and system services.
589+
590+ See sd_booted(3) for more information.
591+*/
592+int netsnmp_sd_booted(void);
593+
594+/**
595+ * Find an socket with given parameters. See man sd_is_socket_inet for
596+ * description of the arguments.
597+ *
598+ * Returns the file descriptor if it is found, 0 otherwise.
599+ */
600+int netsnmp_sd_find_inet_socket(int family, int type, int listening, int port);
601+
602+/**
603+ * Find an unix socket with given parameters. See man sd_is_socket_unix for
604+ * description of the arguments.
605+ *
606+ * Returns the file descriptor if it is found, 0 otherwise.
607+ */
608+int
609+netsnmp_sd_find_unix_socket(int type, int listening, const char *path);
610+
611+#ifdef __cplusplus
612+}
613+#endif
614+
615+#endif /* SNMPD_SD_DAEMON_H */
616diff --git a/snmplib/sd-daemon.c b/snmplib/sd-daemon.c
617new file mode 100644
618index 0000000..42dba29
619--- /dev/null
620+++ b/snmplib/sd-daemon.c
621@@ -0,0 +1,532 @@
622+/*
623+ * Systemd integration parts.
624+ *
625+ * Most of this file is directly copied from systemd sources.
626+ * Changes:
627+ * - all functions were renamed to have netsnmp_ prefix
628+ * - includes were changed to match Net-SNMP style.
629+ * - removed gcc export macros
630+ * - removed POSIX message queues
631+ */
632+
633+#include <net-snmp/net-snmp-config.h>
634+#include <net-snmp/net-snmp-features.h>
635+#include <net-snmp/types.h>
636+#include <net-snmp/library/snmp_debug.h>
637+
638+#ifndef NETSNMP_NO_SYSTEMD
639+
640+/***
641+ Copyright 2010 Lennart Poettering
642+
643+ Permission is hereby granted, free of charge, to any person
644+ obtaining a copy of this software and associated documentation files
645+ (the "Software"), to deal in the Software without restriction,
646+ including without limitation the rights to use, copy, modify, merge,
647+ publish, distribute, sublicense, and/or sell copies of the Software,
648+ and to permit persons to whom the Software is furnished to do so,
649+ subject to the following conditions:
650+
651+ The above copyright notice and this permission notice shall be
652+ included in all copies or substantial portions of the Software.
653+
654+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
655+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
656+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
657+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
658+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
659+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
660+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
661+ SOFTWARE.
662+***/
663+
664+#ifndef _GNU_SOURCE
665+#define _GNU_SOURCE
666+#endif
667+
668+#include <sys/types.h>
669+#include <sys/stat.h>
670+#include <sys/socket.h>
671+#include <sys/un.h>
672+#include <sys/fcntl.h>
673+#include <netinet/in.h>
674+#include <stdlib.h>
675+#include <errno.h>
676+#include <unistd.h>
677+#include <string.h>
678+#include <stdarg.h>
679+#include <stdio.h>
680+#include <stddef.h>
681+#include <limits.h>
682+
683+#include <net-snmp/library/sd-daemon.h>
684+
685+int netsnmp_sd_listen_fds(int unset_environment) {
686+
687+ int r, fd;
688+ const char *e;
689+ char *p = NULL;
690+ unsigned long l;
691+
692+ if (!(e = getenv("LISTEN_PID"))) {
693+ r = 0;
694+ goto finish;
695+ }
696+
697+ errno = 0;
698+ l = strtoul(e, &p, 10);
699+
700+ if (errno != 0) {
701+ r = -errno;
702+ goto finish;
703+ }
704+
705+ if (!p || *p || l <= 0) {
706+ r = -EINVAL;
707+ goto finish;
708+ }
709+
710+ /* Is this for us? */
711+ if (getpid() != (pid_t) l) {
712+ r = 0;
713+ goto finish;
714+ }
715+
716+ if (!(e = getenv("LISTEN_FDS"))) {
717+ r = 0;
718+ goto finish;
719+ }
720+
721+ errno = 0;
722+ l = strtoul(e, &p, 10);
723+
724+ if (errno != 0) {
725+ r = -errno;
726+ goto finish;
727+ }
728+
729+ if (!p || *p) {
730+ r = -EINVAL;
731+ goto finish;
732+ }
733+
734+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
735+ int flags;
736+
737+ if ((flags = fcntl(fd, F_GETFD)) < 0) {
738+ r = -errno;
739+ goto finish;
740+ }
741+
742+ if (flags & FD_CLOEXEC)
743+ continue;
744+
745+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
746+ r = -errno;
747+ goto finish;
748+ }
749+ }
750+
751+ r = (int) l;
752+
753+finish:
754+ if (unset_environment) {
755+ unsetenv("LISTEN_PID");
756+ unsetenv("LISTEN_FDS");
757+ }
758+
759+ return r;
760+}
761+
762+int netsnmp_sd_is_fifo(int fd, const char *path) {
763+ struct stat st_fd;
764+
765+ if (fd < 0)
766+ return -EINVAL;
767+
768+ memset(&st_fd, 0, sizeof(st_fd));
769+ if (fstat(fd, &st_fd) < 0)
770+ return -errno;
771+
772+ if (!S_ISFIFO(st_fd.st_mode))
773+ return 0;
774+
775+ if (path) {
776+ struct stat st_path;
777+
778+ memset(&st_path, 0, sizeof(st_path));
779+ if (stat(path, &st_path) < 0) {
780+
781+ if (errno == ENOENT || errno == ENOTDIR)
782+ return 0;
783+
784+ return -errno;
785+ }
786+
787+ return
788+ st_path.st_dev == st_fd.st_dev &&
789+ st_path.st_ino == st_fd.st_ino;
790+ }
791+
792+ return 1;
793+}
794+
795+int netsnmp_sd_is_special(int fd, const char *path) {
796+ struct stat st_fd;
797+
798+ if (fd < 0)
799+ return -EINVAL;
800+
801+ if (fstat(fd, &st_fd) < 0)
802+ return -errno;
803+
804+ if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
805+ return 0;
806+
807+ if (path) {
808+ struct stat st_path;
809+
810+ if (stat(path, &st_path) < 0) {
811+
812+ if (errno == ENOENT || errno == ENOTDIR)
813+ return 0;
814+
815+ return -errno;
816+ }
817+
818+ if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
819+ return
820+ st_path.st_dev == st_fd.st_dev &&
821+ st_path.st_ino == st_fd.st_ino;
822+ else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
823+ return st_path.st_rdev == st_fd.st_rdev;
824+ else
825+ return 0;
826+ }
827+
828+ return 1;
829+}
830+
831+static int sd_is_socket_internal(int fd, int type, int listening) {
832+ struct stat st_fd;
833+
834+ if (fd < 0 || type < 0)
835+ return -EINVAL;
836+
837+ if (fstat(fd, &st_fd) < 0)
838+ return -errno;
839+
840+ if (!S_ISSOCK(st_fd.st_mode))
841+ return 0;
842+
843+ if (type != 0) {
844+ int other_type = 0;
845+ socklen_t l = sizeof(other_type);
846+
847+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
848+ return -errno;
849+
850+ if (l != sizeof(other_type))
851+ return -EINVAL;
852+
853+ if (other_type != type)
854+ return 0;
855+ }
856+
857+ if (listening >= 0) {
858+ int accepting = 0;
859+ socklen_t l = sizeof(accepting);
860+
861+ if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
862+ return -errno;
863+
864+ if (l != sizeof(accepting))
865+ return -EINVAL;
866+
867+ if (!accepting != !listening)
868+ return 0;
869+ }
870+
871+ return 1;
872+}
873+
874+union sockaddr_union {
875+ struct sockaddr sa;
876+ struct sockaddr_in in4;
877+ struct sockaddr_in6 in6;
878+ struct sockaddr_un un;
879+ struct sockaddr_storage storage;
880+};
881+
882+int netsnmp_sd_is_socket(int fd, int family, int type, int listening) {
883+ int r;
884+
885+ if (family < 0)
886+ return -EINVAL;
887+
888+ if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
889+ return r;
890+
891+ if (family > 0) {
892+ union sockaddr_union sockaddr;
893+ socklen_t l;
894+
895+ memset(&sockaddr, 0, sizeof(sockaddr));
896+ l = sizeof(sockaddr);
897+
898+ if (getsockname(fd, &sockaddr.sa, &l) < 0)
899+ return -errno;
900+
901+ if (l < sizeof(sa_family_t))
902+ return -EINVAL;
903+
904+ return sockaddr.sa.sa_family == family;
905+ }
906+
907+ return 1;
908+}
909+
910+int netsnmp_sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
911+ union sockaddr_union sockaddr;
912+ socklen_t l;
913+ int r;
914+
915+ if (family != 0 && family != AF_INET && family != AF_INET6)
916+ return -EINVAL;
917+
918+ if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
919+ return r;
920+
921+ memset(&sockaddr, 0, sizeof(sockaddr));
922+ l = sizeof(sockaddr);
923+
924+ if (getsockname(fd, &sockaddr.sa, &l) < 0)
925+ return -errno;
926+
927+ if (l < sizeof(sa_family_t))
928+ return -EINVAL;
929+
930+ if (sockaddr.sa.sa_family != AF_INET &&
931+ sockaddr.sa.sa_family != AF_INET6)
932+ return 0;
933+
934+ if (family > 0)
935+ if (sockaddr.sa.sa_family != family)
936+ return 0;
937+
938+ if (port > 0) {
939+ if (sockaddr.sa.sa_family == AF_INET) {
940+ if (l < sizeof(struct sockaddr_in))
941+ return -EINVAL;
942+
943+ return htons(port) == sockaddr.in4.sin_port;
944+ } else {
945+ if (l < sizeof(struct sockaddr_in6))
946+ return -EINVAL;
947+
948+ return htons(port) == sockaddr.in6.sin6_port;
949+ }
950+ }
951+
952+ return 1;
953+}
954+
955+int netsnmp_sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
956+ union sockaddr_union sockaddr;
957+ socklen_t l;
958+ int r;
959+
960+ if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
961+ return r;
962+
963+ memset(&sockaddr, 0, sizeof(sockaddr));
964+ l = sizeof(sockaddr);
965+
966+ if (getsockname(fd, &sockaddr.sa, &l) < 0)
967+ return -errno;
968+
969+ if (l < sizeof(sa_family_t))
970+ return -EINVAL;
971+
972+ if (sockaddr.sa.sa_family != AF_UNIX)
973+ return 0;
974+
975+ if (path) {
976+ if (length <= 0)
977+ length = strlen(path);
978+
979+ if (length <= 0)
980+ /* Unnamed socket */
981+ return l == offsetof(struct sockaddr_un, sun_path);
982+
983+ if (path[0])
984+ /* Normal path socket */
985+ return
986+ (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
987+ memcmp(path, sockaddr.un.sun_path, length+1) == 0;
988+ else
989+ /* Abstract namespace socket */
990+ return
991+ (l == offsetof(struct sockaddr_un, sun_path) + length) &&
992+ memcmp(path, sockaddr.un.sun_path, length) == 0;
993+ }
994+
995+ return 1;
996+}
997+
998+int netsnmp_sd_notify(int unset_environment, const char *state) {
999+ int fd = -1, r;
1000+ struct msghdr msghdr;
1001+ struct iovec iovec;
1002+ union sockaddr_union sockaddr;
1003+ const char *e;
1004+
1005+ if (!state) {
1006+ r = -EINVAL;
1007+ goto finish;
1008+ }
1009+
1010+ if (!(e = getenv("NOTIFY_SOCKET")))
1011+ return 0;
1012+
1013+ /* Must be an abstract socket, or an absolute path */
1014+ if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
1015+ r = -EINVAL;
1016+ goto finish;
1017+ }
1018+
1019+ if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
1020+ r = -errno;
1021+ goto finish;
1022+ }
1023+
1024+ memset(&sockaddr, 0, sizeof(sockaddr));
1025+ sockaddr.sa.sa_family = AF_UNIX;
1026+ strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
1027+
1028+ if (sockaddr.un.sun_path[0] == '@')
1029+ sockaddr.un.sun_path[0] = 0;
1030+
1031+ memset(&iovec, 0, sizeof(iovec));
1032+ iovec.iov_base = (char *)state;
1033+ iovec.iov_len = strlen(state);
1034+
1035+ memset(&msghdr, 0, sizeof(msghdr));
1036+ msghdr.msg_name = &sockaddr;
1037+ msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
1038+
1039+ if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
1040+ msghdr.msg_namelen = sizeof(struct sockaddr_un);
1041+
1042+ msghdr.msg_iov = &iovec;
1043+ msghdr.msg_iovlen = 1;
1044+
1045+ if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
1046+ r = -errno;
1047+ goto finish;
1048+ }
1049+
1050+ r = 1;
1051+
1052+finish:
1053+ if (unset_environment)
1054+ unsetenv("NOTIFY_SOCKET");
1055+
1056+ if (fd >= 0)
1057+ close(fd);
1058+
1059+ return r;
1060+}
1061+
1062+int netsnmp_sd_notifyf(int unset_environment, const char *format, ...) {
1063+ va_list ap;
1064+ char *p = NULL;
1065+ int r;
1066+
1067+ va_start(ap, format);
1068+ r = vasprintf(&p, format, ap);
1069+ va_end(ap);
1070+
1071+ if (r < 0 || !p)
1072+ return -ENOMEM;
1073+
1074+ r = netsnmp_sd_notify(unset_environment, p);
1075+ free(p);
1076+
1077+ return r;
1078+}
1079+
1080+int netsnmp_sd_booted(void) {
1081+ struct stat a, b;
1082+
1083+ /* We simply test whether the systemd cgroup hierarchy is
1084+ * mounted */
1085+
1086+ if (lstat("/sys/fs/cgroup", &a) < 0)
1087+ return 0;
1088+
1089+ if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
1090+ return 0;
1091+
1092+ return a.st_dev != b.st_dev;
1093+}
1094+
1095+/* End of original sd-daemon.c from systemd sources */
1096+
1097+int
1098+netsnmp_sd_find_inet_socket(int family, int type, int listening, int port)
1099+{
1100+ int count, fd;
1101+
1102+ count = netsnmp_sd_listen_fds(0);
1103+ if (count <= 0) {
1104+ DEBUGMSGTL(("systemd:find_inet_socket", "No LISTEN_FDS found.\n"));
1105+ return 0;
1106+ }
1107+ DEBUGMSGTL(("systemd:find_inet_socket", "LISTEN_FDS reports %d sockets.\n",
1108+ count));
1109+
1110+ for (fd = 3; fd < 3+count; fd++) {
1111+ int rc = netsnmp_sd_is_socket_inet(fd, family, type, listening, port);
1112+ if (rc < 0)
1113+ DEBUGMSGTL(("systemd:find_inet_socket",
1114+ "sd_is_socket_inet error: %d\n", rc));
1115+ if (rc > 0) {
1116+ DEBUGMSGTL(("systemd:find_inet_socket",
1117+ "Found the socket in LISTEN_FDS\n"));
1118+ return fd;
1119+ }
1120+ }
1121+ DEBUGMSGTL(("systemd:find_inet_socket", "Socket not found in LISTEN_FDS\n"));
1122+ return 0;
1123+}
1124+
1125+int
1126+netsnmp_sd_find_unix_socket(int type, int listening, const char *path)
1127+{
1128+ int count, fd;
1129+
1130+ count = netsnmp_sd_listen_fds(0);
1131+ if (count <= 0) {
1132+ DEBUGMSGTL(("systemd:find_unix_socket", "No LISTEN_FDS found.\n"));
1133+ return 0;
1134+ }
1135+ DEBUGMSGTL(("systemd:find_unix_socket", "LISTEN_FDS reports %d sockets.\n",
1136+ count));
1137+
1138+ for (fd = 3; fd < 3+count; fd++) {
1139+ int rc = netsnmp_sd_is_socket_unix(fd, type, listening, path, 0);
1140+ if (rc < 0)
1141+ DEBUGMSGTL(("systemd:find_unix_socket",
1142+ "netsnmp_sd_is_socket_unix error: %d\n", rc));
1143+ if (rc > 0) {
1144+ DEBUGMSGTL(("systemd:find_unix_socket",
1145+ "Found the socket in LISTEN_FDS\n"));
1146+ return fd;
1147+ }
1148+ }
1149+ DEBUGMSGTL(("systemd:find_unix_socket", "Socket not found in LISTEN_FDS\n"));
1150+ return 0;
1151+}
1152+
1153+#endif /* ! NETSNMP_NO_SYSTEMD */
1154diff --git a/snmplib/transports/snmpTCPDomain.c b/snmplib/transports/snmpTCPDomain.c
1155index b8bdba4..ab7f3a1 100644
1156--- a/snmplib/transports/snmpTCPDomain.c
1157+++ b/snmplib/transports/snmpTCPDomain.c
1158@@ -43,6 +43,10 @@
1159 #include <net-snmp/library/snmpTCPBaseDomain.h>
1160 #include <net-snmp/library/tools.h>
1161
1162+#ifndef NETSNMP_NO_SYSTEMD
1163+#include <net-snmp/library/sd-daemon.h>
1164+#endif
1165+
1166 /*
1167 * needs to be in sync with the definitions in snmplib/snmpUDPDomain.c
1168 * and perl/agent/agent.xs
1169@@ -149,6 +153,7 @@ netsnmp_tcp_transport(struct sockaddr_in *addr, int local)
1170 netsnmp_transport *t = NULL;
1171 netsnmp_udp_addr_pair *addr_pair = NULL;
1172 int rc = 0;
1173+ int socket_initialized = 0;
1174
1175 #ifdef NETSNMP_NO_LISTEN_SUPPORT
1176 if (local)
1177@@ -178,7 +183,19 @@ netsnmp_tcp_transport(struct sockaddr_in *addr, int local)
1178 t->domain_length =
1179 sizeof(netsnmp_snmpTCPDomain) / sizeof(netsnmp_snmpTCPDomain[0]);
1180
1181- t->sock = socket(PF_INET, SOCK_STREAM, 0);
1182+#ifndef NETSNMP_NO_SYSTEMD
1183+ /*
1184+ * Maybe the socket was already provided by systemd...
1185+ */
1186+ if (local) {
1187+ t->sock = netsnmp_sd_find_inet_socket(PF_INET, SOCK_STREAM, 1,
1188+ ntohs(addr->sin_port));
1189+ if (t->sock)
1190+ socket_initialized = 1;
1191+ }
1192+#endif
1193+ if (!socket_initialized)
1194+ t->sock = socket(PF_INET, SOCK_STREAM, 0);
1195 if (t->sock < 0) {
1196 netsnmp_transport_free(t);
1197 return NULL;
1198@@ -215,11 +232,13 @@ netsnmp_tcp_transport(struct sockaddr_in *addr, int local)
1199 setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt,
1200 sizeof(opt));
1201
1202- rc = bind(t->sock, (struct sockaddr *)addr, sizeof(struct sockaddr));
1203- if (rc != 0) {
1204- netsnmp_socketbase_close(t);
1205- netsnmp_transport_free(t);
1206- return NULL;
1207+ if (!socket_initialized) {
1208+ rc = bind(t->sock, (struct sockaddr *)addr, sizeof(struct sockaddr));
1209+ if (rc != 0) {
1210+ netsnmp_socketbase_close(t);
1211+ netsnmp_transport_free(t);
1212+ return NULL;
1213+ }
1214 }
1215
1216 /*
1217@@ -235,12 +254,13 @@ netsnmp_tcp_transport(struct sockaddr_in *addr, int local)
1218 /*
1219 * Now sit here and wait for connections to arrive.
1220 */
1221-
1222- rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
1223- if (rc != 0) {
1224- netsnmp_socketbase_close(t);
1225- netsnmp_transport_free(t);
1226- return NULL;
1227+ if (!socket_initialized) {
1228+ rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
1229+ if (rc != 0) {
1230+ netsnmp_socketbase_close(t);
1231+ netsnmp_transport_free(t);
1232+ return NULL;
1233+ }
1234 }
1235
1236 /*
1237diff --git a/snmplib/transports/snmpTCPIPv6Domain.c b/snmplib/transports/snmpTCPIPv6Domain.c
1238index 3c96856..305a861 100644
1239--- a/snmplib/transports/snmpTCPIPv6Domain.c
1240+++ b/snmplib/transports/snmpTCPIPv6Domain.c
1241@@ -49,6 +49,10 @@
1242 #include <net-snmp/library/snmpTCPBaseDomain.h>
1243 #include <net-snmp/library/tools.h>
1244
1245+#ifndef NETSNMP_NO_SYSTEMD
1246+#include <net-snmp/library/sd-daemon.h>
1247+#endif
1248+
1249 #include "inet_ntop.h"
1250
1251 oid netsnmp_TCPIPv6Domain[] = { TRANSPORT_DOMAIN_TCP_IPV6 };
1252@@ -140,6 +144,8 @@ netsnmp_tcp6_transport(struct sockaddr_in6 *addr, int local)
1253 {
1254 netsnmp_transport *t = NULL;
1255 int rc = 0;
1256+ char *str = NULL;
1257+ int socket_initialized = 0;
1258
1259 #ifdef NETSNMP_NO_LISTEN_SUPPORT
1260 if (local)
1261@@ -174,7 +180,19 @@ netsnmp_tcp6_transport(struct sockaddr_in6 *addr, int local)
1262 t->domain = netsnmp_TCPIPv6Domain;
1263 t->domain_length = sizeof(netsnmp_TCPIPv6Domain) / sizeof(oid);
1264
1265- t->sock = socket(PF_INET6, SOCK_STREAM, 0);
1266+#ifndef NETSNMP_NO_SYSTEMD
1267+ /*
1268+ * Maybe the socket was already provided by systemd...
1269+ */
1270+ if (local) {
1271+ t->sock = netsnmp_sd_find_inet_socket(PF_INET6, SOCK_STREAM, 1,
1272+ ntohs(addr->sin6_port));
1273+ if (t->sock)
1274+ socket_initialized = 1;
1275+ }
1276+#endif
1277+ if (!socket_initialized)
1278+ t->sock = socket(PF_INET6, SOCK_STREAM, 0);
1279 if (t->sock < 0) {
1280 netsnmp_transport_free(t);
1281 return NULL;
1282@@ -220,12 +238,14 @@ netsnmp_tcp6_transport(struct sockaddr_in6 *addr, int local)
1283
1284 setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
1285
1286- rc = bind(t->sock, (struct sockaddr *) addr,
1287- sizeof(struct sockaddr_in6));
1288- if (rc != 0) {
1289- netsnmp_socketbase_close(t);
1290- netsnmp_transport_free(t);
1291- return NULL;
1292+ if (!socket_initialized) {
1293+ rc = bind(t->sock, (struct sockaddr *) addr,
1294+ sizeof(struct sockaddr_in6));
1295+ if (rc != 0) {
1296+ netsnmp_socketbase_close(t);
1297+ netsnmp_transport_free(t);
1298+ return NULL;
1299+ }
1300 }
1301
1302 /*
1303@@ -242,11 +262,13 @@ netsnmp_tcp6_transport(struct sockaddr_in6 *addr, int local)
1304 * Now sit here and wait for connections to arrive.
1305 */
1306
1307- rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
1308- if (rc != 0) {
1309- netsnmp_socketbase_close(t);
1310- netsnmp_transport_free(t);
1311- return NULL;
1312+ if (!socket_initialized) {
1313+ rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
1314+ if (rc != 0) {
1315+ netsnmp_socketbase_close(t);
1316+ netsnmp_transport_free(t);
1317+ return NULL;
1318+ }
1319 }
1320
1321 /*
1322diff --git a/snmplib/transports/snmpUDPIPv4BaseDomain.c b/snmplib/transports/snmpUDPIPv4BaseDomain.c
1323index c67427b..428e6d6 100644
1324--- a/snmplib/transports/snmpUDPIPv4BaseDomain.c
1325+++ b/snmplib/transports/snmpUDPIPv4BaseDomain.c
1326@@ -40,6 +40,10 @@
1327
1328 #include <net-snmp/library/snmpSocketBaseDomain.h>
1329
1330+#ifndef NETSNMP_NO_SYSTEMD
1331+#include <net-snmp/library/sd-daemon.h>
1332+#endif
1333+
1334 #if (defined(linux) && defined(IP_PKTINFO)) \
1335 || defined(IP_RECVDSTADDR) && HAVE_STRUCT_MSGHDR_MSG_CONTROL \
1336 && HAVE_STRUCT_MSGHDR_MSG_FLAGS
1337@@ -67,6 +71,7 @@ netsnmp_udpipv4base_transport(struct sockaddr_in *addr, int local)
1338 char *client_socket = NULL;
1339 netsnmp_indexed_addr_pair addr_pair;
1340 socklen_t local_addr_len;
1341+ int socket_initialized = 0;
1342
1343 #ifdef NETSNMP_NO_LISTEN_SUPPORT
1344 if (local)
1345@@ -91,7 +96,19 @@ netsnmp_udpipv4base_transport(struct sockaddr_in *addr, int local)
1346 free(str);
1347 }
1348
1349- t->sock = socket(PF_INET, SOCK_DGRAM, 0);
1350+#ifndef NETSNMP_NO_SYSTEMD
1351+ /*
1352+ * Maybe the socket was already provided by systemd...
1353+ */
1354+ if (local) {
1355+ t->sock = netsnmp_sd_find_inet_socket(PF_INET, SOCK_DGRAM, -1,
1356+ ntohs(addr->sin_port));
1357+ if (t->sock)
1358+ socket_initialized = 1;
1359+ }
1360+#endif
1361+ if (!socket_initialized)
1362+ t->sock = socket(PF_INET, SOCK_DGRAM, 0);
1363 DEBUGMSGTL(("UDPBase", "openned socket %d as local=%d\n", t->sock, local));
1364 if (t->sock < 0) {
1365 netsnmp_transport_free(t);
1366@@ -141,12 +158,14 @@ netsnmp_udpipv4base_transport(struct sockaddr_in *addr, int local)
1367 DEBUGMSGTL(("netsnmp_udp", "set IP_RECVDSTADDR\n"));
1368 }
1369 #endif
1370- rc = bind(t->sock, (struct sockaddr *) addr,
1371- sizeof(struct sockaddr));
1372- if (rc != 0) {
1373- netsnmp_socketbase_close(t);
1374- netsnmp_transport_free(t);
1375- return NULL;
1376+ if (!socket_initialized) {
1377+ rc = bind(t->sock, (struct sockaddr *) addr,
1378+ sizeof(struct sockaddr));
1379+ if (rc != 0) {
1380+ netsnmp_socketbase_close(t);
1381+ netsnmp_transport_free(t);
1382+ return NULL;
1383+ }
1384 }
1385 t->data = NULL;
1386 t->data_length = 0;
1387diff --git a/snmplib/transports/snmpUDPIPv6Domain.c b/snmplib/transports/snmpUDPIPv6Domain.c
1388index b3eaae4..35b617f 100644
1389--- a/snmplib/transports/snmpUDPIPv6Domain.c
1390+++ b/snmplib/transports/snmpUDPIPv6Domain.c
1391@@ -67,6 +67,10 @@ static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
1392 #include <net-snmp/library/snmpSocketBaseDomain.h>
1393 #include <net-snmp/library/tools.h>
1394
1395+#ifndef NETSNMP_NO_SYSTEMD
1396+#include <net-snmp/library/sd-daemon.h>
1397+#endif
1398+
1399 #include "inet_ntop.h"
1400 #include "inet_pton.h"
1401
1402@@ -190,6 +194,8 @@ netsnmp_udp6_transport(struct sockaddr_in6 *addr, int local)
1403 {
1404 netsnmp_transport *t = NULL;
1405 int rc = 0;
1406+ char *str = NULL;
1407+ int socket_initialized = 0;
1408
1409 #ifdef NETSNMP_NO_LISTEN_SUPPORT
1410 if (local)
1411@@ -217,7 +223,19 @@ netsnmp_udp6_transport(struct sockaddr_in6 *addr, int local)
1412 t->domain_length =
1413 sizeof(netsnmp_UDPIPv6Domain) / sizeof(netsnmp_UDPIPv6Domain[0]);
1414
1415- t->sock = socket(PF_INET6, SOCK_DGRAM, 0);
1416+#ifndef NETSNMP_NO_SYSTEMD
1417+ /*
1418+ * Maybe the socket was already provided by systemd...
1419+ */
1420+ if (local) {
1421+ t->sock = netsnmp_sd_find_inet_socket(PF_INET6, SOCK_DGRAM, -1,
1422+ ntohs(addr->sin6_port));
1423+ if (t->sock)
1424+ socket_initialized = 1;
1425+ }
1426+#endif
1427+ if (!socket_initialized)
1428+ t->sock = socket(PF_INET6, SOCK_DGRAM, 0);
1429 if (t->sock < 0) {
1430 netsnmp_transport_free(t);
1431 return NULL;
1432@@ -242,13 +260,14 @@ netsnmp_udp6_transport(struct sockaddr_in6 *addr, int local)
1433 }
1434 }
1435 #endif
1436-
1437- rc = bind(t->sock, (struct sockaddr *) addr,
1438- sizeof(struct sockaddr_in6));
1439- if (rc != 0) {
1440- netsnmp_socketbase_close(t);
1441- netsnmp_transport_free(t);
1442- return NULL;
1443+ if (!socket_initialized) {
1444+ rc = bind(t->sock, (struct sockaddr *) addr,
1445+ sizeof(struct sockaddr_in6));
1446+ if (rc != 0) {
1447+ netsnmp_socketbase_close(t);
1448+ netsnmp_transport_free(t);
1449+ return NULL;
1450+ }
1451 }
1452 t->local = (unsigned char*)malloc(18);
1453 if (t->local == NULL) {
1454diff --git a/snmplib/transports/snmpUnixDomain.c b/snmplib/transports/snmpUnixDomain.c
1455index 674dc2b..9f3d3cb 100644
1456--- a/snmplib/transports/snmpUnixDomain.c
1457+++ b/snmplib/transports/snmpUnixDomain.c
1458@@ -37,6 +37,10 @@
1459 #include <net-snmp/library/system.h> /* mkdirhier */
1460 #include <net-snmp/library/tools.h>
1461
1462+#ifndef NETSNMP_NO_SYSTEMD
1463+#include <net-snmp/library/sd-daemon.h>
1464+#endif
1465+
1466 netsnmp_feature_child_of(transport_unix_socket_all, transport_all)
1467 netsnmp_feature_child_of(unix_socket_paths, transport_unix_socket_all)
1468
1469@@ -295,6 +299,8 @@ netsnmp_unix_transport(struct sockaddr_un *addr, int local)
1470 netsnmp_transport *t = NULL;
1471 sockaddr_un_pair *sup = NULL;
1472 int rc = 0;
1473+ char *string = NULL;
1474+ int socket_initialized = 0;
1475
1476 #ifdef NETSNMP_NO_LISTEN_SUPPORT
1477 /* SPECIAL CIRCUMSTANCE: We still want AgentX to be able to operate,
1478@@ -333,7 +339,18 @@ netsnmp_unix_transport(struct sockaddr_un *addr, int local)
1479 t->data_length = sizeof(sockaddr_un_pair);
1480 sup = (sockaddr_un_pair *) t->data;
1481
1482- t->sock = socket(PF_UNIX, SOCK_STREAM, 0);
1483+#ifndef NETSNMP_NO_SYSTEMD
1484+ /*
1485+ * Maybe the socket was already provided by systemd...
1486+ */
1487+ if (local) {
1488+ t->sock = netsnmp_sd_find_unix_socket(SOCK_STREAM, 1, addr->sun_path);
1489+ if (t->sock)
1490+ socket_initialized = 1;
1491+ }
1492+#endif
1493+ if (!socket_initialized)
1494+ t->sock = socket(PF_UNIX, SOCK_STREAM, 0);
1495 if (t->sock < 0) {
1496 netsnmp_transport_free(t);
1497 return NULL;
1498@@ -357,25 +374,26 @@ netsnmp_unix_transport(struct sockaddr_un *addr, int local)
1499
1500 t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;
1501
1502- unlink(addr->sun_path);
1503- rc = bind(t->sock, (struct sockaddr *) addr, SUN_LEN(addr));
1504-
1505- if (rc != 0 && errno == ENOENT && create_path) {
1506- rc = mkdirhier(addr->sun_path, create_mode, 1);
1507+ if (!socket_initialized) {
1508+ unlink(addr->sun_path);
1509+ rc = bind(t->sock, (struct sockaddr *) addr, SUN_LEN(addr));
1510+ if (rc != 0 && errno == ENOENT && create_path) {
1511+ rc = mkdirhier(addr->sun_path, create_mode, 1);
1512+ if (rc != 0) {
1513+ netsnmp_unix_close(t);
1514+ netsnmp_transport_free(t);
1515+ return NULL;
1516+ }
1517+ rc = bind(t->sock, (struct sockaddr *) addr, SUN_LEN(addr));
1518+ }
1519 if (rc != 0) {
1520+ DEBUGMSGTL(("netsnmp_unix_transport",
1521+ "couldn't bind \"%s\", errno %d (%s)\n",
1522+ addr->sun_path, errno, strerror(errno)));
1523 netsnmp_unix_close(t);
1524 netsnmp_transport_free(t);
1525 return NULL;
1526 }
1527- rc = bind(t->sock, (struct sockaddr *) addr, SUN_LEN(addr));
1528- }
1529- if (rc != 0) {
1530- DEBUGMSGTL(("netsnmp_unix_transport",
1531- "couldn't bind \"%s\", errno %d (%s)\n",
1532- addr->sun_path, errno, strerror(errno)));
1533- netsnmp_unix_close(t);
1534- netsnmp_transport_free(t);
1535- return NULL;
1536 }
1537
1538 /*
1539@@ -391,16 +409,17 @@ netsnmp_unix_transport(struct sockaddr_un *addr, int local)
1540 * Now sit here and listen for connections to arrive.
1541 */
1542
1543- rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
1544- if (rc != 0) {
1545- DEBUGMSGTL(("netsnmp_unix_transport",
1546- "couldn't listen to \"%s\", errno %d (%s)\n",
1547- addr->sun_path, errno, strerror(errno)));
1548- netsnmp_unix_close(t);
1549- netsnmp_transport_free(t);
1550- return NULL;
1551+ if (!socket_initialized) {
1552+ rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
1553+ if (rc != 0) {
1554+ DEBUGMSGTL(("netsnmp_unix_transport",
1555+ "couldn't listen to \"%s\", errno %d (%s)\n",
1556+ addr->sun_path, errno, strerror(errno)));
1557+ netsnmp_unix_close(t);
1558+ netsnmp_transport_free(t);
1559+ return NULL;
1560+ }
1561 }
1562-
1563 } else {
1564 t->remote = (u_char *)malloc(strlen(addr->sun_path));
1565 if (t->remote == NULL) {
1566diff --git a/win32/libsnmp/Makefile.in b/win32/libsnmp/Makefile.in
1567index 98d83c8..dd5689b 100644
1568--- a/win32/libsnmp/Makefile.in
1569+++ b/win32/libsnmp/Makefile.in
1570@@ -42,6 +42,7 @@ LIB32_OBJS= \
1571 "$(INTDIR)\read_config.obj" \
1572 "$(INTDIR)\readdir.obj" \
1573 "$(INTDIR)\scapi.obj" \
1574+ "$(INTDIR)\sd-daemon.obj" \
1575 "$(INTDIR)\snmp-tc.obj" \
1576 "$(INTDIR)\snmp.obj" \
1577 "$(INTDIR)\snmpCallbackDomain.obj" \
1578@@ -307,6 +308,12 @@ SOURCE=..\..\snmplib\scapi.c
1579 $(CPP) $(CPP_PROJ) $(SOURCE)
1580
1581
1582+SOURCE=..\..\snmplib\sd-daemon.c
1583+
1584+"$(INTDIR)\sd-daemon.obj" : $(SOURCE) "$(INTDIR)"
1585+ $(CPP) $(CPP_PROJ) $(SOURCE)
1586+
1587+
1588 SOURCE="..\..\snmplib\snmp-tc.c"
1589
1590 "$(INTDIR)\snmp-tc.obj" : $(SOURCE) "$(INTDIR)"
1591diff --git a/win32/net-snmp/net-snmp-config.h b/win32/net-snmp/net-snmp-config.h
1592index 7791ee0..1eccf42 100644
1593--- a/win32/net-snmp/net-snmp-config.h
1594+++ b/win32/net-snmp/net-snmp-config.h
1595@@ -1705,6 +1705,8 @@ enum {
1596 #define DMALLOC_FUNC_CHECK
1597 #endif
1598
1599+#define NETSNMP_NO_SYSTEMD
1600+
1601 /* #undef NETSNMP_ENABLE_LOCAL_SMUX */
1602
1603 /* define if agentx transport is to use domain sockets only */
1604diff --git a/win32/net-snmp/net-snmp-config.h.in b/win32/net-snmp/net-snmp-config.h.in
1605index 5215865..1607bfa 100644
1606--- a/win32/net-snmp/net-snmp-config.h.in
1607+++ b/win32/net-snmp/net-snmp-config.h.in
1608@@ -1705,6 +1705,8 @@ enum {
1609 #define DMALLOC_FUNC_CHECK
1610 #endif
1611
1612+#define NETSNMP_NO_SYSTEMD
1613+
1614 /* #undef NETSNMP_ENABLE_LOCAL_SMUX */
1615
1616 /* define if agentx transport is to use domain sockets only */