From 41327992680cfb8dd602ea92d6902448dd66413d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Sep 2010 13:06:04 +0200 Subject: acquire /dev/log socket optionally from systemd --- ChangeLog | 2 ++ plugins/imuxsock/Makefile.am | 4 +-- plugins/imuxsock/imuxsock.c | 50 ++++++++++++++++++++++++++++++++---- runtime/Makefile.am | 5 ++++ tools/Makefile.am | 2 +- tools/syslogd.c | 61 +++++++++++++++++++++++--------------------- 6 files changed, 87 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index da9379c2..f4bdc6ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +- acquire /dev/log socket optionally from systemd + thanks to Lennart Poettering for this patch --------------------------------------------------------------------------- Version 5.5.6 [DEVEL] (rgerhards), 2010-06-?? - added parser modules diff --git a/plugins/imuxsock/Makefile.am b/plugins/imuxsock/Makefile.am index a2fe0baa..8803937f 100644 --- a/plugins/imuxsock/Makefile.am +++ b/plugins/imuxsock/Makefile.am @@ -1,6 +1,6 @@ pkglib_LTLIBRARIES = imuxsock.la -imuxsock_la_SOURCES = imuxsock.c +imuxsock_la_SOURCES = imuxsock.c ../../runtime/sd-daemon.c ../../runtime/sd-daemon.h imuxsock_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imuxsock_la_LDFLAGS = -module -avoid-version -imuxsock_la_LIBADD = +imuxsock_la_LIBADD = diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 046f12f0..db53fcb6 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -47,6 +47,7 @@ #include "prop.h" #include "debug.h" #include "unlimited_select.h" +#include "sd-daemon.h" MODULE_TYPE_INPUT @@ -74,7 +75,7 @@ DEFobjCurrIf(prop) static prop_t *pLocalHostIP = NULL; /* there is only one global IP for all internally-generated messages */ static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */ -static int startIndexUxLocalSockets; /* process funix from that index on (used to +static int startIndexUxLocalSockets; /* process funix from that index on (used to * suppress local logging. rgerhards 2005-08-01 * read-only after startup */ @@ -177,7 +178,7 @@ static rsRetVal discardFunixn(void) prop.Destruct(&(funixHName[i])); } } - + return RS_RET_OK; } @@ -190,6 +191,40 @@ static int create_unix_socket(const char *path, int bCreatePath) if (path[0] == '\0') return -1; + if (strcmp(path, _PATH_LOG) == 0) { + int r; + + /* Check whether an FD was passed in from systemd. If + * so, it's the /dev/log socket, so use it. */ + + r = sd_listen_fds(0); + if (r < 0) { + errmsg.LogError(-r, NO_ERRCODE, "Failed to acquire systemd socket"); + return -1; + } + + if (r > 1) { + errmsg.LogError(EINVAL, NO_ERRCODE, "Wrong number of systemd sockets passed"); + return -1; + } + + if (r == 1) { + fd = SD_LISTEN_FDS_START; + r = sd_is_socket_unix(fd, SOCK_DGRAM, -1, _PATH_LOG, 0); + if (r < 0) { + errmsg.LogError(-r, NO_ERRCODE, "Failed to verify systemd socket type"); + return -1; + } + + if (!r) { + errmsg.LogError(EINVAL, NO_ERRCODE, "Passed systemd socket of wrong type"); + return -1; + } + + return fd; + } + } + unlink(path); memset(&sunx, 0, sizeof(sunx)); @@ -391,12 +426,17 @@ CODESTARTafterRun int i; /* do cleanup here */ /* Close the UNIX sockets. */ - for (i = 0; i < nfunix; i++) + for (i = 0; i < nfunix; i++) if (funix[i] != -1) close(funix[i]); - /* Clean-up files. */ - for(i = startIndexUxLocalSockets; i < nfunix; i++) + /* Clean-up files. If systemd passed us a socket it is + * systemd's job to clean it up.*/ + if (sd_listen_fds(0) > 0) + i = 1; + else + i = startIndexUxLocalSockets; + for(; i < nfunix; i++) if (funixn[i] && funix[i] != -1) unlink((char*) funixn[i]); /* free no longer needed string */ diff --git a/runtime/Makefile.am b/runtime/Makefile.am index f7db3e35..ef119492 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -81,6 +81,8 @@ librsyslog_la_SOURCES = \ prop.h \ cfsysline.c \ cfsysline.h \ + sd-daemon.c \ + sd-daemon.h \ \ \ ../action.h \ @@ -177,3 +179,6 @@ lmnsd_gtls_la_LDFLAGS = -module -avoid-version lmnsd_gtls_la_LIBADD = $(GNUTLS_LIBS) endif +update-systemd: + curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c > sd-daemon.c + curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h > sd-daemon.h diff --git a/tools/Makefile.am b/tools/Makefile.am index 8f2989ca..96657ad4 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,5 +1,5 @@ sbin_PROGRAMS = -man_MANS = rsyslogd.8 rsyslog.conf.5 +man_MANS = rsyslogd.8 rsyslog.conf.5 sbin_PROGRAMS += rsyslogd rsyslogd_SOURCES = \ diff --git a/tools/syslogd.c b/tools/syslogd.c index 9b7b77ab..a7f76313 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -135,6 +135,7 @@ #include "net.h" #include "vm.h" #include "prop.h" +#include "sd-daemon.h" /* definitions for objects we access */ DEFobjCurrIf(obj) @@ -391,7 +392,7 @@ static char **crunch_list(char *list) char **result = NULL; p = list; - + /* strip off trailing delimiters */ while (p[strlen(p)-1] == LIST_DELIMITER) { count--; @@ -400,18 +401,18 @@ static char **crunch_list(char *list) /* cut off leading delimiters */ while (p[0] == LIST_DELIMITER) { count--; - p++; + p++; } - + /* count delimiters to calculate elements */ for (count=i=0; p[i]; i++) if (p[i] == LIST_DELIMITER) count++; - + if ((result = (char **)MALLOC(sizeof(char *) * (count+2))) == NULL) { printf ("Sorry, can't get enough memory, exiting.\n"); exit(0); /* safe exit, because only called during startup */ } - + /* * We now can assume that the first and last * characters are different from any delimiters, @@ -574,7 +575,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) if(bHaveMainQueue == 0) { /* not yet in queued mode */ iminternalAddMsg(pri, pMsg); } else { - /* we have the queue, so we can simply provide the + /* we have the queue, so we can simply provide the * message to the queue engine. */ submitMsg(pMsg); @@ -721,7 +722,7 @@ submitMsg(msg_t *pMsg) DEFiRet; ISOBJ_TYPE_assert(pMsg, msg); - + pRuleset = MsgGetRuleset(pMsg); pQueue = (pRuleset == NULL) ? pMsgQueue : ruleset.GetRulesetQueue(pRuleset); @@ -787,7 +788,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) { action_t *pAction = (action_t*) pData; assert(pAction != NULL); - + BEGINfunc LockObj(pAction); /* TODO: time() performance: the call below could be moved to @@ -842,7 +843,7 @@ static void debug_switch() dbgprintf("\n"); debugging_on = 0; } - + memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); sigAct.sa_handler = debug_switch; @@ -1030,7 +1031,7 @@ destructAllActions(void) /* die() is called when the program shall end. This typically only occurs - * during sigterm or during the initialization. + * during sigterm or during the initialization. * As die() is intended to shutdown rsyslogd, it is * safe to call exit() here. Just make sure that die() itself is not called * at inapropriate places. As a general rule of thumb, it is a bad idea to add @@ -1070,7 +1071,7 @@ die(int sig) errno = 0; logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); } - + /* drain queue (if configured so) and stop main queue worker thread pool */ DBGPRINTF("Terminating main queue...\n"); qqueueDestruct(&pMsgQueue); @@ -1194,7 +1195,7 @@ static rsRetVal setUmask(void __attribute__((unused)) *pVal, int iUmask) } -/* drop to specified group +/* drop to specified group * if something goes wrong, the function never returns * Note that such an abort can cause damage to on-disk structures, so we should * re-design the "interface" in the long term. -- rgerhards, 2008-11-26 @@ -1222,7 +1223,7 @@ static void doDropPrivGid(int iGid) } -/* drop to specified user +/* drop to specified user * if something goes wrong, the function never returns * Note that such an abort can cause damage to on-disk structures, so we should * re-design the "interface" in the long term. -- rgerhards, 2008-11-19 @@ -1332,7 +1333,7 @@ generateConfigDAG(uchar *pszDAGFile) DEFiRet; assert(pszDAGFile != NULL); - + if((fp = fopen((char*) pszDAGFile, "w")) == NULL) { logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*) "configuraton graph output file could not be opened, none generated", 0); @@ -1458,7 +1459,7 @@ static void dbgPrintInitInfo(void) /* TODO: add iActionRetryCount = 0; iActionRetryInterval = 30000; - static int iMainMsgQtoWrkMinMsgs = 100; + static int iMainMsgQtoWrkMinMsgs = 100; static int iMainMsgQbSaveOnShutdown = 1; iMainMsgQueMaxDiskSpace = 0; setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100); @@ -1730,7 +1731,7 @@ init(void) * identify this instance. -- rgerhards, 2005-08-17 */ if(bLogStatusMsgs) { - snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), + snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] start", (int) myPid); @@ -1760,7 +1761,7 @@ finalize_it: -/* Put the rsyslog main thread to sleep for n seconds. This was introduced as +/* Put the rsyslog main thread to sleep for n seconds. This was introduced as * a quick and dirty workaround for a privilege drop race in regard to listener * startup, which itself was a result of the not-yet-done proper coding of * privilege drop code (quite some effort). It may be useful for other occasions, too. @@ -1845,7 +1846,7 @@ static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *psz void sighup_handler() { struct sigaction sigAct; - + bHadHUP = 1; memset(&sigAct, 0, sizeof (sigAct)); @@ -2428,8 +2429,10 @@ doGlblProcessInit(void) num_fds = getdtablesize(); close(0); /* we keep stdout and stderr open in case we have to emit something */ - for (i = 3; i < num_fds; i++) - (void) close(i); + + if (sd_listen_fds(0) <= 0) + for (i = 3; i < num_fds; i++) + (void) close(i); untty(); } else @@ -2486,7 +2489,7 @@ doGlblProcessInit(void) * modularize it a bit more... */ int realMain(int argc, char **argv) -{ +{ DEFiRet; register uchar *p; @@ -2516,7 +2519,7 @@ int realMain(int argc, char **argv) * of other options, we do this during the inital option processing. With later * versions (if a dependency on -c option is introduced), we must move that code * to other places, but I think it is quite appropriate and saves code to do this - * only when actually neeeded. + * only when actually neeeded. * rgerhards, 2008-04-04 */ while((ch = getopt(argc, argv, "46a:Ac:def:g:hi:l:m:M:nN:op:qQr::s:t:T:u:vwx")) != EOF) { @@ -2581,7 +2584,7 @@ int realMain(int argc, char **argv) case 'v': /* MUST be carried out immediately! */ printVersion(); exit(0); /* exit for -v option - so this is a "good one" */ - case '?': + case '?': default: usage(); } @@ -2637,7 +2640,7 @@ int realMain(int argc, char **argv) * Good software also always checks its return values... * If syslogd starts up before DNS is up & /etc/hosts * doesn't have LocalHostName listed, gethostbyname will - * return NULL. + * return NULL. */ /* TODO: gethostbyname() is not thread-safe, but replacing it is * not urgent as we do not run on multiple threads here. rgerhards, 2007-09-25 @@ -2646,7 +2649,7 @@ int realMain(int argc, char **argv) if(hent) { free(LocalHostName); CHKmalloc(LocalHostName = (uchar*)strdup(hent->h_name)); - + if((p = (uchar*)strchr((char*)LocalHostName, '.'))) { *p++ = '\0'; @@ -2658,7 +2661,7 @@ int realMain(int argc, char **argv) /* Convert to lower case to recognize the correct domain laterly */ for(p = LocalDomain ; *p ; p++) *p = (char)tolower((int)*p); - + /* we now have our hostname and can set it inside the global vars. * TODO: think if all of this would better be a runtime function * rgerhards, 2008-04-17 @@ -2814,7 +2817,7 @@ int realMain(int argc, char **argv) case 'x': /* disable dns for remote messages */ glbl.SetDisableDNS(1); break; - case '?': + case '?': default: usage(); } @@ -2871,7 +2874,7 @@ int realMain(int argc, char **argv) /* do any de-init's that need to be done AFTER this comment */ die(bFinished); - + thrdExit(); finalize_it: @@ -2893,7 +2896,7 @@ finalize_it: * rgerhards, 20080-01-28 */ int main(int argc, char **argv) -{ +{ dbgClassInit(); return realMain(argc, argv); } -- cgit v1.2.3 From 3e2d011e8c1c42801194d387b75ca4f4a175ae5d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 7 Sep 2010 14:19:05 +0200 Subject: added forgotten files --- runtime/sd-daemon.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/sd-daemon.h | 257 ++++++++++++++++++++++++++++++ 2 files changed, 705 insertions(+) create mode 100644 runtime/sd-daemon.c create mode 100644 runtime/sd-daemon.h diff --git a/runtime/sd-daemon.c b/runtime/sd-daemon.c new file mode 100644 index 00000000..5df70e38 --- /dev/null +++ b/runtime/sd-daemon.c @@ -0,0 +1,448 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + Copyright 2010 Lennart Poettering + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +***/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-daemon.h" + +int sd_listen_fds(int unset_environment) { + +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + int r, fd; + const char *e; + char *p = NULL; + unsigned long l; + + if (!(e = getenv("LISTEN_PID"))) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno != 0) { + r = -errno; + goto finish; + } + + if (!p || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + /* Is this for us? */ + if (getpid() != (pid_t) l) { + r = 0; + goto finish; + } + + if (!(e = getenv("LISTEN_FDS"))) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno != 0) { + r = -errno; + goto finish; + } + + if (!p || *p) { + r = -EINVAL; + goto finish; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { + int flags; + + if ((flags = fcntl(fd, F_GETFD)) < 0) { + r = -errno; + goto finish; + } + + if (flags & FD_CLOEXEC) + continue; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { + r = -errno; + goto finish; + } + } + + r = (int) l; + +finish: + if (unset_environment) { + unsetenv("LISTEN_PID"); + unsetenv("LISTEN_FDS"); + } + + return r; +#endif +} + +int sd_is_fifo(int fd, const char *path) { + struct stat st_fd; + + if (fd < 0) + return -EINVAL; + + memset(&st_fd, 0, sizeof(st_fd)); + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISFIFO(st_fd.st_mode)) + return 0; + + if (path) { + struct stat st_path; + + memset(&st_path, 0, sizeof(st_path)); + if (stat(path, &st_path) < 0) { + + if (errno == ENOENT || errno == ENOTDIR) + return 0; + + return -errno; + } + + return + st_path.st_dev == st_fd.st_dev && + st_path.st_ino == st_fd.st_ino; + } + + return 1; +} + +static int sd_is_socket_internal(int fd, int type, int listening) { + struct stat st_fd; + + if (fd < 0 || type < 0) + return -EINVAL; + + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISSOCK(st_fd.st_mode)) + return 0; + + if (type != 0) { + int other_type = 0; + socklen_t l = sizeof(other_type); + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) + return -errno; + + if (l != sizeof(other_type)) + return -EINVAL; + + if (other_type != type) + return 0; + } + + if (listening >= 0) { + int accepting = 0; + socklen_t l = sizeof(accepting); + + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) + return -errno; + + if (l != sizeof(accepting)) + return -EINVAL; + + if (!accepting != !listening) + return 0; + } + + return 1; +} + +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_storage storage; +}; + +int sd_is_socket(int fd, int family, int type, int listening) { + int r; + + if (family < 0) + return -EINVAL; + + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) + return r; + + if (family > 0) { + union sockaddr_union sockaddr; + socklen_t l; + + memset(&sockaddr, 0, sizeof(sockaddr)); + l = sizeof(sockaddr); + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + return sockaddr.sa.sa_family == family; + } + + return 1; +} + +int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { + union sockaddr_union sockaddr; + socklen_t l; + int r; + + if (family != 0 && family != AF_INET && family != AF_INET6) + return -EINVAL; + + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) + return r; + + memset(&sockaddr, 0, sizeof(sockaddr)); + l = sizeof(sockaddr); + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + if (sockaddr.sa.sa_family != AF_INET && + sockaddr.sa.sa_family != AF_INET6) + return 0; + + if (family > 0) + if (sockaddr.sa.sa_family != family) + return 0; + + if (port > 0) { + if (sockaddr.sa.sa_family == AF_INET) { + if (l < sizeof(struct sockaddr_in)) + return -EINVAL; + + return htons(port) == sockaddr.in4.sin_port; + } else { + if (l < sizeof(struct sockaddr_in6)) + return -EINVAL; + + return htons(port) == sockaddr.in6.sin6_port; + } + } + + return 1; +} + +int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { + union sockaddr_union sockaddr; + socklen_t l; + int r; + + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) + return r; + + memset(&sockaddr, 0, sizeof(sockaddr)); + l = sizeof(sockaddr); + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + if (sockaddr.sa.sa_family != AF_UNIX) + return 0; + + if (path) { + if (length <= 0) + length = strlen(path); + + if (length <= 0) + /* Unnamed socket */ + return l == sizeof(sa_family_t); + + if (path[0]) + /* Normal path socket */ + return + (l >= sizeof(sa_family_t) + length + 1) && + memcmp(path, sockaddr.un.sun_path, length+1) == 0; + else + /* Abstract namespace socket */ + return + (l == sizeof(sa_family_t) + length) && + memcmp(path, sockaddr.un.sun_path, length) == 0; + } + + return 1; +} + +int sd_notify(int unset_environment, const char *state) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + int fd = -1, r; + struct msghdr msghdr; + struct iovec iovec; + union sockaddr_union sockaddr; + struct ucred *ucred; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control; + const char *e; + + if (!state) { + r = -EINVAL; + goto finish; + } + + if (!(e = getenv("NOTIFY_SOCKET"))) + return 0; + + /* Must be an abstract socket, or an absolute path */ + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { + r = -EINVAL; + goto finish; + } + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { + r = -errno; + goto finish; + } + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sa.sa_family = AF_UNIX; + strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); + + if (sockaddr.un.sun_path[0] == '@') + sockaddr.un.sun_path[0] = 0; + + memset(&iovec, 0, sizeof(iovec)); + iovec.iov_base = (char*) state; + iovec.iov_len = strlen(state); + + memset(&control, 0, sizeof(control)); + control.cmsghdr.cmsg_level = SOL_SOCKET; + control.cmsghdr.cmsg_type = SCM_CREDENTIALS; + control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred)); + + ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + ucred->pid = getpid(); + ucred->uid = getuid(); + ucred->gid = getgid(); + + memset(&msghdr, 0, sizeof(msghdr)); + msghdr.msg_name = &sockaddr; + msghdr.msg_namelen = sizeof(struct sockaddr_un); + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = &control; + msghdr.msg_controllen = control.cmsghdr.cmsg_len; + + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { + r = -errno; + goto finish; + } + + r = 1; + +finish: + if (unset_environment) + unsetenv("NOTIFY_SOCKET"); + + if (fd >= 0) + close(fd); + + return r; +#endif +} + +int sd_notifyf(int unset_environment, const char *format, ...) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + va_list ap; + char *p = NULL; + int r; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0 || !p) + return -ENOMEM; + + r = sd_notify(unset_environment, p); + free(p); + + return r; +#endif +} + +int sd_booted(void) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + + struct stat a, b; + + /* We simply test whether the systemd cgroup hierarchy is + * mounted */ + + if (lstat("/cgroup", &a) < 0) + return 0; + + if (lstat("/cgroup/systemd", &b) < 0) + return 0; + + return a.st_dev != b.st_dev; +#endif +} diff --git a/runtime/sd-daemon.h b/runtime/sd-daemon.h new file mode 100644 index 00000000..fd6221f2 --- /dev/null +++ b/runtime/sd-daemon.h @@ -0,0 +1,257 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +#ifndef foosddaemonhfoo +#define foosddaemonhfoo + +/*** + Copyright 2010 Lennart Poettering + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +***/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Reference implementation of a few systemd related interfaces for + writing daemons. These interfaces are trivial to implement. To + simplify porting we provide this reference implementation. + Applications are welcome to reimplement the algorithms described + here if they do not want to include these two source files. + + The following functionality is provided: + + - Support for logging with log levels on stderr + - File descriptor passing for socket-based activation + - Daemon startup and status notification + - Detection of systemd boots + + You may compile this with -DDISABLE_SYSTEMD to disable systemd + support. This makes all those calls NOPs that are directly related to + systemd (i.e. only sd_is_xxx() will stay useful). + + Since this is drop-in code we don't want any of our symbols to be + exported in any case. Hence we declare hidden visibility for all of + them. + + You may find an up-to-date version of these source files online: + + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h + http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c + + This should compile on non-Linux systems, too, but with the + exception of the sd_is_xxx() calls all functions will become NOPs. + + See sd-daemon(7) for more information. +*/ + +#if __GNUC__ >= 4 +#define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b))) +#define _sd_hidden_ __attribute__ ((visibility("hidden"))) +#else +#define _sd_printf_attr_(a,b) +#define _sd_hidden_ +#endif + +/* + Log levels for usage on stderr: + + fprintf(stderr, SD_NOTICE "Hello World!\n"); + + This is similar to printk() usage in the kernel. +*/ +#define SD_EMERG "<0>" /* system is unusable */ +#define SD_ALERT "<1>" /* action must be taken immediately */ +#define SD_CRIT "<2>" /* critical conditions */ +#define SD_ERR "<3>" /* error conditions */ +#define SD_WARNING "<4>" /* warning conditions */ +#define SD_NOTICE "<5>" /* normal but significant condition */ +#define SD_INFO "<6>" /* informational */ +#define SD_DEBUG "<7>" /* debug-level messages */ + +/* The first passed file descriptor is fd 3 */ +#define SD_LISTEN_FDS_START 3 + +/* + Returns how many file descriptors have been passed, or a negative + errno code on failure. Optionally, removes the $LISTEN_FDS and + $LISTEN_PID file descriptors from the environment (recommended, but + problematic in threaded environments). If r is the return value of + this function you'll find the file descriptors passed as fds + SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative + errno style error code on failure. This function call ensures that + the FD_CLOEXEC flag is set for the passed file descriptors, to make + sure they are not passed on to child processes. If FD_CLOEXEC shall + not be set, the caller needs to unset it after this call for all file + descriptors that are used. + + See sd_listen_fds(3) for more information. +*/ +int sd_listen_fds(int unset_environment) _sd_hidden_; + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is a FIFO in the file system stored under the + specified path, 0 otherwise. If path is NULL a path name check will + not be done and the call only verifies if the file descriptor + refers to a FIFO. Returns a negative errno style error code on + failure. + + See sd_is_fifo(3) for more information. +*/ +int sd_is_fifo(int fd, const char *path) _sd_hidden_; + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is a socket of the specified family (AF_INET, + ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If + family is 0 a socket family check will not be done. If type is 0 a + socket type check will not be done and the call only verifies if + the file descriptor refers to a socket. If listening is > 0 it is + verified that the socket is in listening mode. (i.e. listen() has + been called) If listening is == 0 it is verified that the socket is + not in listening mode. If listening is < 0 no listening mode check + is done. Returns a negative errno style error code on failure. + + See sd_is_socket(3) for more information. +*/ +int sd_is_socket(int fd, int family, int type, int listening) _sd_hidden_; + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is an Internet socket, of the specified family + (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM, + SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version + check is not done. If type is 0 a socket type check will not be + done. If port is 0 a socket port check will not be done. The + listening flag is used the same way as in sd_is_socket(). Returns a + negative errno style error code on failure. + + See sd_is_socket_inet(3) for more information. +*/ +int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) _sd_hidden_; + +/* + Helper call for identifying a passed file descriptor. Returns 1 if + the file descriptor is an AF_UNIX socket of the specified type + (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0 + a socket type check will not be done. If path is NULL a socket path + check will not be done. For normal AF_UNIX sockets set length to + 0. For abstract namespace sockets set length to the length of the + socket name (including the initial 0 byte), and pass the full + socket path in path (including the initial 0 byte). The listening + flag is used the same way as in sd_is_socket(). Returns a negative + errno style error code on failure. + + See sd_is_socket_unix(3) for more information. +*/ +int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) _sd_hidden_; + +/* + Informs systemd about changed daemon state. This takes a number of + newline seperated environment-style variable assignments in a + string. The following variables are known: + + READY=1 Tells systemd that daemon startup is finished (only + relevant for services of Type=notify). The passed + argument is a boolean "1" or "0". Since there is + little value in signalling non-readiness the only + value daemons should send is "READY=1". + + STATUS=... Passes a single-line status string back to systemd + that describes the daemon state. This is free-from + and can be used for various purposes: general state + feedback, fsck-like programs could pass completion + percentages and failing programs could pass a human + readable error message. Example: "STATUS=Completed + 66% of file system check..." + + ERRNO=... If a daemon fails, the errno-style error code, + formatted as string. Example: "ERRNO=2" for ENOENT. + + BUSERROR=... If a daemon fails, the D-Bus error-style error + code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut" + + MAINPID=... The main pid of a daemon, in case systemd did not + fork off the process itself. Example: "MAINPID=4711" + + Daemons can choose to send additional variables. However, it is + recommened to prefix variable names not listed above with X_. + + Returns a negative errno-style error code on failure. Returns > 0 + if systemd could be notified, 0 if it couldn't possibly because + systemd is not running. + + Example: When a daemon finished starting up, it could issue this + call to notify systemd about it: + + sd_notify(0, "READY=1"); + + See sd_notifyf() for more complete examples. + + See sd_notify(3) for more information. +*/ +int sd_notify(int unset_environment, const char *state) _sd_hidden_; + +/* + Similar to sd_notify() but takes a format string. + + Example 1: A daemon could send the following after initialization: + + sd_notifyf(0, "READY=1\n" + "STATUS=Processing requests...\n" + "MAINPID=%lu", + (unsigned long) getpid()); + + Example 2: A daemon could send the following shortly before + exiting, on failure: + + sd_notifyf(0, "STATUS=Failed to start up: %s\n" + "ERRNO=%i", + strerror(errno), + errno); + + See sd_notifyf(3) for more information. +*/ +int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3) _sd_hidden_; + +/* + Returns > 0 if the system was booted with systemd. Returns < 0 on + error. Returns 0 if the system was not booted with systemd. Note + that all of the functions above handle non-systemd boots just + fine. You should NOT protect them with a call to this function. Also + note that this function checks whether the system, not the user + session is controlled by systemd. However the functions above work + for both session and system services. + + See sd_booted(3) for more information. +*/ +int sd_booted(void) _sd_hidden_; + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3 From 21a2672222a1b403ff0811154dec156676bed732 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 8 Sep 2010 12:46:03 +0200 Subject: moved systemd interface to rsyslog convenience lib Mostly a refresh of sd-daemon.[ch] from its source plus some make file changes. We now have systemd interfaces inside rsyslog, so that all plugins interested can call the interfaces. Seems not to be totally necessary right now, but will help in the long term. --- plugins/imuxsock/Makefile.am | 6 +++--- runtime/Makefile.am | 4 ++-- runtime/sd-daemon.c | 31 +++++++++---------------------- runtime/sd-daemon.h | 12 ++++++++---- 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/plugins/imuxsock/Makefile.am b/plugins/imuxsock/Makefile.am index 8803937f..28f9f9e3 100644 --- a/plugins/imuxsock/Makefile.am +++ b/plugins/imuxsock/Makefile.am @@ -1,6 +1,6 @@ pkglib_LTLIBRARIES = imuxsock.la -imuxsock_la_SOURCES = imuxsock.c ../../runtime/sd-daemon.c ../../runtime/sd-daemon.h -imuxsock_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +imuxsock_la_SOURCES = imuxsock.c +imuxsock_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) imuxsock_la_LDFLAGS = -module -avoid-version -imuxsock_la_LIBADD = +imuxsock_la_LIBADD = $(RSRT_LIBS) diff --git a/runtime/Makefile.am b/runtime/Makefile.am index ef119492..5b2598b2 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -101,9 +101,9 @@ librsyslog_la_SOURCES = \ # runtime or will no longer be needed. -- rgerhards, 2008-06-13 if WITH_MODDIRS -librsyslog_la_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) else -librsyslog_la_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) endif #librsyslog_la_LDFLAGS = -module -avoid-version librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) diff --git a/runtime/sd-daemon.c b/runtime/sd-daemon.c index 5df70e38..9c23b917 100644 --- a/runtime/sd-daemon.c +++ b/runtime/sd-daemon.c @@ -1,4 +1,4 @@ -/*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** Copyright 2010 Lennart Poettering @@ -325,18 +325,13 @@ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t } int sd_notify(int unset_environment, const char *state) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) return 0; #else int fd = -1, r; struct msghdr msghdr; struct iovec iovec; union sockaddr_union sockaddr; - struct ucred *ucred; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; const char *e; if (!state) { @@ -369,23 +364,15 @@ int sd_notify(int unset_environment, const char *state) { iovec.iov_base = (char*) state; iovec.iov_len = strlen(state); - memset(&control, 0, sizeof(control)); - control.cmsghdr.cmsg_level = SOL_SOCKET; - control.cmsghdr.cmsg_type = SCM_CREDENTIALS; - control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred)); - - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - ucred->pid = getpid(); - ucred->uid = getuid(); - ucred->gid = getgid(); - memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = &sockaddr; - msghdr.msg_namelen = sizeof(struct sockaddr_un); + msghdr.msg_namelen = sizeof(sa_family_t) + strlen(e); + + if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) + msghdr.msg_namelen = sizeof(struct sockaddr_un); + msghdr.msg_iov = &iovec; msghdr.msg_iovlen = 1; - msghdr.msg_control = &control; - msghdr.msg_controllen = control.cmsghdr.cmsg_len; if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { r = -errno; @@ -437,10 +424,10 @@ int sd_booted(void) { /* We simply test whether the systemd cgroup hierarchy is * mounted */ - if (lstat("/cgroup", &a) < 0) + if (lstat("/sys/fs/cgroup", &a) < 0) return 0; - if (lstat("/cgroup/systemd", &b) < 0) + if (lstat("/sys/fs/cgroup/systemd", &b) < 0) return 0; return a.st_dev != b.st_dev; diff --git a/runtime/sd-daemon.h b/runtime/sd-daemon.h index fd6221f2..45aac8bd 100644 --- a/runtime/sd-daemon.h +++ b/runtime/sd-daemon.h @@ -1,4 +1,4 @@ -/*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ #ifndef foosddaemonhfoo #define foosddaemonhfoo @@ -67,9 +67,13 @@ extern "C" { See sd-daemon(7) for more information. */ -#if __GNUC__ >= 4 +#if (__GNUC__ >= 4) #define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b))) -#define _sd_hidden_ __attribute__ ((visibility("hidden"))) +# if defined(SD_EXPORT_SYMBOLS) +# define _sd_hidden_ +# else +# define _sd_hidden_ __attribute__ ((visibility("hidden"))) +# endif #else #define _sd_printf_attr_(a,b) #define _sd_hidden_ @@ -171,7 +175,7 @@ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t /* Informs systemd about changed daemon state. This takes a number of - newline seperated environment-style variable assignments in a + newline separated environment-style variable assignments in a string. The following variables are known: READY=1 Tells systemd that daemon startup is finished (only -- cgit v1.2.3 From 947e5632039d1dd2ef3ae22ac45b17370bbac24d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 8 Sep 2010 13:26:33 +0200 Subject: bumped version number (new v5-devel) --- ChangeLog | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1b6d57cc..cfd1831d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +--------------------------------------------------------------------------- +Version 5.7.0 [V5-DEVEL] (rgerhards), 2010-09-?? +- support for systemd officially added - acquire /dev/log socket optionally from systemd thanks to Lennart Poettering for this patch --------------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 9e0aad5c..9c005a19 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[5.5.7],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.7.0],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3