From 171ac321f1e97a60fbda3858c4c84d60d0b7dacb Mon Sep 17 00:00:00 2001 From: Alec Leamas Date: Wed, 9 Oct 2013 20:57:12 +0200 Subject: [PATCH 104/105] Add systemd socket activation support. Since systemd was introduced lirc clients have had problems at startup when trying to connect to the lircd socket before it's created. The root cause is the aggressive parallell boot performed by systemd. The solution is to add socket activation. In this mode, the socket is created by systemd and handed over to lircd at startup. The patch implements this. It should be reasonably transparent. At configure time it enables systemd support if it's available, otherwise it's silently ignored. In runtime lircd looks for and uses a socket handed over by systemd. If there is no such socket it proceeds as normal. Adds a dependency on pkg-config for the PKG_CHECK_MODULES macro. --- configure.ac | 7 +++++ daemons/lircd.c | 94 ++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/configure.ac b/configure.ac index af28e4f..7df186a 100644 --- a/configure.ac +++ b/configure.ac @@ -232,6 +232,9 @@ AH_TEMPLATE([HAVE_SCSI], AH_TEMPLATE([HAVE_SOUNDCARD], [defined if soundcard API is available]) +AH_TEMPLATE([HAVE_SYSTEMD], + [defined if systemd API is available]) + AH_TEMPLATE([HAVE_VSYSLOG], [define if you have vsyslog( prio, fmt, va_arg )]) @@ -414,6 +417,10 @@ AC_CHECK_HEADERS(linux/i2c-dev.h,[ ] ) +PKG_CHECK_MODULES([SYSTEMD],[libsystemd-daemon],[AC_DEFINE(HAVE_SYSTEMD)],[true]) +CFLAGS="$CFLAGS $SYSTEMD_CFLAGS" +LIBS="$LIBS $SYSTEMD_LIBS" + dnl here we see what driver the user wants. AC_ARG_WITH(driver, diff --git a/daemons/lircd.c b/daemons/lircd.c index 8ace7af..9cde69b 100644 --- a/daemons/lircd.c +++ b/daemons/lircd.c @@ -63,6 +63,10 @@ #include "input_map.h" #endif +#ifdef HAVE_SYSTEMD +#include "systemd/sd-daemon.h" +#endif + #if defined __APPLE__ || defined __FreeBSD__ #include #endif @@ -855,6 +859,7 @@ void start_server(mode_t permission, int nodaemon) int ret; int new = 1; int fd; + int n; /* create pid lockfile in /var/run */ if ((fd = open(pidfile, O_RDWR | O_CREAT, 0644)) == -1 || (pidf = fdopen(fd, "r+")) == NULL) { @@ -881,51 +886,64 @@ void start_server(mode_t permission, int nodaemon) (void)ftruncate(fileno(pidf), ftell(pidf)); /* create socket */ - sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - if (sockfd == -1) { - fprintf(stderr, "%s: could not create socket\n", progname); - perror(progname); + sockfd = -1; +#ifdef HAVE_SYSTEMD + n = sd_listen_fds(0); + if (n > 1) { + fprintf(stderr, "Too many file descriptors received.\n"); goto start_server_failed0; - } + exit(1); + } + else if (n == 1) + sockfd = SD_LISTEN_FDS_START + 0; +#endif + if (sockfd == -1) { + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd == -1) { + fprintf(stderr, "%s: could not create socket\n", progname); + perror(progname); + goto start_server_failed0; + } - /* - get owner, permissions, etc. - so new socket can be the same since we - have to delete the old socket. - */ - ret = stat(lircdfile, &s); - if (ret == -1 && errno != ENOENT) { - fprintf(stderr, "%s: could not get file information for %s\n", progname, lircdfile); - perror(progname); - goto start_server_failed1; - } - if (ret != -1) { - new = 0; - ret = unlink(lircdfile); - if (ret == -1) { - fprintf(stderr, "%s: could not delete %s\n", progname, lircdfile); - perror(NULL); + /* + get owner, permissions, etc. + so new socket can be the same since we + have to delete the old socket. + */ + ret = stat(lircdfile, &s); + if (ret == -1 && errno != ENOENT) { + fprintf(stderr, "%s: could not get file information for %s\n", progname, lircdfile); + perror(progname); goto start_server_failed1; } - } + if (ret != -1) { + new = 0; + ret = unlink(lircdfile); + if (ret == -1) { + fprintf(stderr, "%s: could not delete %s\n", progname, lircdfile); + perror(NULL); + goto start_server_failed1; + } + } - serv_addr.sun_family = AF_UNIX; - strcpy(serv_addr.sun_path, lircdfile); - if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { - fprintf(stderr, "%s: could not assign address to socket\n", progname); - perror(progname); - goto start_server_failed1; - } + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, lircdfile); + if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { + fprintf(stderr, "%s: could not assign address to socket\n", progname); + perror(progname); + goto start_server_failed1; + } - if (new ? chmod(lircdfile, permission) - : (chmod(lircdfile, s.st_mode) == -1 || chown(lircdfile, s.st_uid, s.st_gid) == -1) - ) { - fprintf(stderr, "%s: could not set file permissions\n", progname); - perror(progname); - goto start_server_failed1; - } + if (new ? chmod(lircdfile, permission) + : (chmod(lircdfile, s.st_mode) == -1 || chown(lircdfile, s.st_uid, s.st_gid) == -1) + ) { + fprintf(stderr, "%s: could not set file permissions\n", progname); + perror(progname); + goto start_server_failed1; + } - listen(sockfd, 3); + listen(sockfd, 3); + } nolinger(sockfd); if (useuinput) { -- 1.8.3.1