From 37772340771e643c830b21c83113694ed1927a4c Mon Sep 17 00:00:00 2001 From: Petr Rockai Date: Fri, 13 May 2011 09:34:12 +0000 Subject: [PATCH] More scavenging of common daemon code, this time the clvmd local socket setup sequence. --- daemons/common/daemon-server.c | 62 ++++++++++++++++++++++++++++++++-- daemons/common/daemon-server.h | 4 +++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/daemons/common/daemon-server.c b/daemons/common/daemon-server.c index 8b013c140..1594364ee 100644 --- a/daemons/common/daemon-server.c +++ b/daemons/common/daemon-server.c @@ -79,6 +79,53 @@ static int _set_oom_adj(int val) } #endif +static int _open_socket(daemon_state s) +{ + int fd = -1; + struct sockaddr_un sockaddr; + mode_t old_mask; + + (void) dm_prepare_selinux_context(s.socket_path, S_IFSOCK); + old_mask = umask(0077); + + /* Open local socket */ + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + log_error("Can't create local socket: %m"); + goto error; + } + + /* Set Close-on-exec & non-blocking */ + if (fcntl(fd, F_SETFD, 1)) + DEBUGLOG("setting CLOEXEC on socket fd %d failed: %s\n", fd, strerror(errno)); + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + + memset(&sockaddr, 0, sizeof(sockaddr)); + memcpy(sockaddr.sun_path, s.socket_path, strlen(s.socket_path)); + sockaddr.sun_family = AF_UNIX; + + if (bind(fd, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) { + log_error("can't bind local socket: %m"); + goto error; + } + if (listen(fd, 1) != 0) { + log_error("listen local: %m"); + goto error; + } + +out: + umask(old_mask); + (void) dm_prepare_selinux_context(NULL, 0); + return fd; + +error: + if (fd >= 0) { + close(fd); + fd = -1; + } + goto out; +} + static void remove_lockfile(const char *file) { if (unlink(file)) @@ -155,6 +202,7 @@ static void _daemonise(void) void daemon_start(daemon_state s, handle_request r) { + int failed = 0; /* * Switch to C locale to avoid reading large locale-archive file used by * some glibc (on some distributions it takes over 100MB). Some daemons @@ -172,8 +220,8 @@ void daemon_start(daemon_state s, handle_request r) (void) dm_prepare_selinux_context(s.pidfile, S_IFREG); /* - * NB. Past this point, exit is not allowed. You have to return to this - * function at all costs. More or less. + * NB. Take care to not keep stale locks around. Best not exit(...) + * after this point. */ if (dm_create_lockfile(s.pidfile) == 0) exit(1); @@ -190,15 +238,23 @@ void daemon_start(daemon_state s, handle_request r) syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer"); #endif + if (s.socket_path) { + s.socket_fd = _open_socket(s); + if (s.socket_fd < 0) + failed = 1; + } + /* Signal parent, letting them know we are ready to go. */ if (!s.foreground) kill(getppid(), SIGTERM); - while (!_shutdown_requested) { + while (!_shutdown_requested && !failed) { /* TODO: do work */ } syslog(LOG_NOTICE, "%s shutting down", s.name); closelog(); remove_lockfile(s.pidfile); + if (failed) + exit(1); } diff --git a/daemons/common/daemon-server.h b/daemons/common/daemon-server.h index 77882bc66..2e6ccfaff 100644 --- a/daemons/common/daemon-server.h +++ b/daemons/common/daemon-server.h @@ -35,6 +35,10 @@ typedef struct { unsigned foreground:1; const char *name; const char *pidfile; + const char *socket_path; + + /* Global runtime info maintained by the framework. */ + int socket_fd; void *private; /* the global daemon state */ } daemon_state;