summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEckhart Wörner <ewoerner@kde.org>2011-04-29 14:27:58 -0400
committerEric S. Raymond <esr@thyrsus.com>2011-04-29 14:27:58 -0400
commit5b963265dfdcc99ad37e06f82be17b25751e57a6 (patch)
tree9ca6d11370a762e2956f4c5b15008ba7ef58bd27
parent20ee83fe8ab703e27e37bf2c348d1278667837e3 (diff)
downloadgpsd-5b963265dfdcc99ad37e06f82be17b25751e57a6.tar.gz
Mac OS X systemd activation for gpsd.
The attached patch allows to use gpsd together with socket activation in systemd. The idea is that systemd listens to the control socket and TCP sockets and, as soon as someone connects to them, starts gpsd and passes the file descriptors over (without accept()ing itself). Sockets are in the following order: fd 3 is the control socket, followed by up to two TCP sockets (for IPv4 and IPv6). If no socket passing happens, behaviour of gpsd should be the same as before. For using this new feature, one could use the following config *skeleton*: -> File /etc/systemd/system/gpsd.socket: [Socket] ListenStream=/var/run/gpsd.sock ListenStream=127.0.0.1:2947 -> File /etc/systemd/system/gpsd.service: [Unit] Requires=gpsd.spcket [Service] type=simple ExecStart=/usr/bin/gpsd -N What has been tested: - gpsd compiles fine with both systemd=true/false - Socket activation on the TCP socket works (gpsd is started, version string is sent) What has not been tested: - Socket activation on the control socket works Signed-off-by: Eric S. Raymond <esr@thyrsus.com>
-rw-r--r--SConstruct4
-rw-r--r--gpsd.c32
-rw-r--r--sd_socket.c33
3 files changed, 68 insertions, 1 deletions
diff --git a/SConstruct b/SConstruct
index 0d860f93..8bbcd1c7 100644
--- a/SConstruct
+++ b/SConstruct
@@ -83,6 +83,7 @@ boolopts = (
# Other daemon options
("timing", True, "latency timing support"),
("control_socket",True, "control socket for hotplug notifications"),
+ ("systemd", True, "systemd socket activation"),
# Client-side options
("clientdebug", True, "client debugging support"),
("oldstyle", True, "oldstyle (pre-JSON) protocol support"),
@@ -680,6 +681,9 @@ gpsdlibs = ["-lgpsd"] + usblibs + bluezlibs + gpslibs
gpsd_sources = ['gpsd.c','ntpshm.c','shmexport.c','dbusexport.c']
+if env['systemd']:
+ gpsd_sources.append("sd_socket.c")
+
gpsmon_sources = [
'gpsmon.c',
'monitor_italk.c',
diff --git a/gpsd.c b/gpsd.c
index bfaefd60..5041407a 100644
--- a/gpsd.c
+++ b/gpsd.c
@@ -52,6 +52,10 @@
#include "gps_json.h"
#include "revision.h"
+#if defined(SYSTEMD_ENABLE)
+#include "sd_socket.h"
+#endif
+
/*
* The name of a tty device from which to pick up whatever the local
* owning group for tty devices is. Used when we drop privileges.
@@ -145,6 +149,7 @@ static bool nowait = false;
#endif /* FORCE_NOWAIT */
static jmp_buf restartbuf;
static struct gps_context_t context;
+static int sd_socket_count = 0;
static volatile sig_atomic_t signalled;
@@ -465,6 +470,15 @@ static int passivesocks(char *service, char *tcp_or_udp,
for (i = 0; i < AFCOUNT; i++)
socks[i] = -1;
+#if defined(SYSTEMD_ENABLE)
+ if (sd_socket_count > 0) {
+ for (i = 0; i < AFCOUNT && i < sd_socket_count - 1; i++) {
+ socks[i] = SD_SOCKET_FDS_START + i + 1;
+ }
+ return sd_socket_count - 1;
+ }
+#endif
+
if (AF_UNSPEC == af || (AF_INET == af))
socks[0] = passivesock_af(AF_INET, service, tcp_or_udp, qlen);
@@ -1798,8 +1812,17 @@ int main(int argc, char *argv[])
}
}
+#ifdef SYSTEMD_ENABLE
+ sd_socket_count = sd_get_socket_count();
+ if (sd_socket_count > 0 && control_socket) {
+ gpsd_report(LOG_WARN,
+ "control socket passed on command line ignored\n");
+ control_socket = NULL;
+ }
+#endif
+
#ifdef CONTROL_SOCKET_ENABLE
- if (!control_socket && optind >= argc) {
+ if (!control_socket && optind >= argc && sd_socket_count <= 0) {
gpsd_report(LOG_ERROR,
"can't run with neither control socket nor devices\n");
exit(1);
@@ -1810,6 +1833,13 @@ int main(int argc, char *argv[])
* avoid a race condition in which hotplug scripts can try opening
* the socket before it's created.
*/
+#ifdef SYSTEMD_ENABLE
+ if (sd_socket_count > 0) {
+ csock = SD_SOCKET_FDS_START;
+ FD_SET(csock, &all_fds);
+ adjust_max_fd(csock, true);
+ }
+#endif
if (control_socket) {
(void)unlink(control_socket);
if ((csock = filesock(control_socket)) == -1) {
diff --git a/sd_socket.c b/sd_socket.c
new file mode 100644
index 00000000..8c8c7719
--- /dev/null
+++ b/sd_socket.c
@@ -0,0 +1,33 @@
+/*
+ * This file is Copyright (c) 2011 by Eckhart Wörner
+ * BSD terms apply: see the file COPYING in the distribution root for details.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "sd_socket.h"
+
+int sd_get_socket_count(void) {
+ unsigned long n;
+ const char* env;
+
+ env = getenv("LISTEN_PID");
+ if (!env)
+ return 0;
+
+ n = strtoul(env, NULL, 10);
+ if (n == ULONG_MAX || (pid_t)n != getpid())
+ return 0;
+
+ env = getenv("LISTEN_FDS");
+ if (!env)
+ return 0;
+
+ n = strtoul(env, NULL, 10);
+ if (n == ULONG_MAX)
+ return 0;
+
+ return (int)n;
+}