summaryrefslogtreecommitdiffstats
path: root/misc-utils/uuidd.c
diff options
context:
space:
mode:
authorSami Kerola2015-10-03 20:31:06 +0200
committerKarel Zak2015-10-09 11:17:11 +0200
commit25d66b4e3232d7b004e51114d7fff5e40b0224b2 (patch)
treed85aea2b93a7f62470fdb4860be40891b760a44f /misc-utils/uuidd.c
parentblkid, uuidd, uuidgen: assume getopt.h and getopt.h are available (diff)
downloadkernel-qcow2-util-linux-25d66b4e3232d7b004e51114d7fff5e40b0224b2.tar.gz
kernel-qcow2-util-linux-25d66b4e3232d7b004e51114d7fff5e40b0224b2.tar.xz
kernel-qcow2-util-linux-25d66b4e3232d7b004e51114d7fff5e40b0224b2.zip
uuidd: use signalfd() and setup_timer()
Point of this change is to replace use of signal() and alarm() system calls using newer interfaces. Nice side effect is that the point where timer was earlier used cannot be distracted by sending rogue SIGALRM. Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Diffstat (limited to 'misc-utils/uuidd.c')
-rw-r--r--misc-utils/uuidd.c135
1 files changed, 96 insertions, 39 deletions
diff --git a/misc-utils/uuidd.c b/misc-utils/uuidd.c
index e19be52cd..c897372d5 100644
--- a/misc-utils/uuidd.c
+++ b/misc-utils/uuidd.c
@@ -22,6 +22,8 @@
#include <signal.h>
#include <string.h>
#include <getopt.h>
+#include <sys/signalfd.h>
+#include <poll.h>
#include "uuid.h"
#include "uuidd.h"
@@ -30,6 +32,8 @@
#include "closestream.h"
#include "strutils.h"
#include "optutils.h"
+#include "monotonic.h"
+#include "timer.h"
#ifdef HAVE_LIBSYSTEMD
# include <systemd/sd-daemon.h>
@@ -51,6 +55,8 @@
/* server loop control structure */
struct uuidd_cxt_t {
+ const char *cleanup_pidfile;
+ const char *cleanup_socket;
uint32_t timeout;
unsigned int debug: 1,
quiet: 1,
@@ -96,17 +102,6 @@ static void create_daemon(void)
err(EXIT_FAILURE, "setreuid");
}
-static const char *cleanup_pidfile, *cleanup_socket;
-
-static void terminate_intr(int signo CODE_ATTR((unused)))
-{
- if (cleanup_pidfile)
- unlink(cleanup_pidfile);
- if (cleanup_socket)
- unlink(cleanup_socket);
- exit(EXIT_SUCCESS);
-}
-
static int call_daemon(const char *socket_path, int op, char *buf,
size_t buflen, int *num, const char **err_context)
{
@@ -199,12 +194,10 @@ static int call_daemon(const char *socket_path, int op, char *buf,
/*
* Exclusively create and open a pid file with path @pidfile_path
*
- * Set cleanup_pidfile global variable for the cleanup
- * handler. @pidfile_path must not be NULL.
- *
* Return file descriptor of the created pid_file.
*/
-static int create_pidfile(const char *pidfile_path, int quiet)
+static int create_pidfile(struct uuidd_cxt_t *uuidd_cxt,
+ const char *pidfile_path, int quiet)
{
int fd_pidfile;
struct flock fl;
@@ -215,7 +208,7 @@ static int create_pidfile(const char *pidfile_path, int quiet)
warn(_("cannot open %s"), pidfile_path);
exit(EXIT_FAILURE);
}
- cleanup_pidfile = pidfile_path;
+ uuidd_cxt->cleanup_pidfile = pidfile_path;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
@@ -242,14 +235,15 @@ static int create_pidfile(const char *pidfile_path, int quiet)
*
* Return file descriptor corresponding to created socket.
*/
-static int create_socket(const char *socket_path, int will_fork, int quiet)
+static int create_socket(struct uuidd_cxt_t *uuidd_cxt,
+ const char *socket_path, int will_fork)
{
struct sockaddr_un my_addr;
mode_t save_umask;
int s;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- if (!quiet)
+ if (!uuidd_cxt->quiet)
warn(_("couldn't create unix stream socket"));
exit(EXIT_FAILURE);
}
@@ -274,18 +268,52 @@ static int create_socket(const char *socket_path, int will_fork, int quiet)
save_umask = umask(0);
if (bind(s, (const struct sockaddr *) &my_addr,
sizeof(struct sockaddr_un)) < 0) {
- if (!quiet)
+ if (!uuidd_cxt->quiet)
warn(_("couldn't bind unix socket %s"), socket_path);
exit(EXIT_FAILURE);
}
umask(save_umask);
- cleanup_socket = socket_path;
+ uuidd_cxt->cleanup_socket = socket_path;
return s;
}
+static void __attribute__((__noreturn__)) all_done(const struct uuidd_cxt_t *uuidd_cxt, int ret)
+{
+ if (uuidd_cxt->cleanup_pidfile)
+ unlink(uuidd_cxt->cleanup_pidfile);
+ if (uuidd_cxt->cleanup_socket)
+ unlink(uuidd_cxt->cleanup_socket);
+ exit(ret);
+}
+
+static void handle_signal(const struct uuidd_cxt_t *uuidd_cxt, int fd)
+{
+ struct signalfd_siginfo info;
+ ssize_t bytes;
+
+ bytes = read(fd, &info, sizeof(info));
+ if (bytes != sizeof(info)) {
+ if (errno == EAGAIN)
+ return;
+ warn(_("receiving signal failed"));
+ info.ssi_signo = 0;
+ }
+ if (info.ssi_signo == SIGPIPE)
+ return; /* ignored */
+ all_done(uuidd_cxt, EXIT_SUCCESS);
+}
+
+static void timeout_handler(int sig __attribute__((__unused__)),
+ siginfo_t * info,
+ void *context __attribute__((__unused__)))
+{
+ if (info->si_code == SI_TIMER)
+ errx(EXIT_FAILURE, _("timed out"));
+}
+
static void server_loop(const char *socket_path, const char *pidfile_path,
- const struct uuidd_cxt_t *uuidd_cxt)
+ struct uuidd_cxt_t *uuidd_cxt)
{
struct sockaddr_un from_addr;
socklen_t fromlen;
@@ -297,30 +325,39 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
int s = 0;
int fd_pidfile = -1;
int ret;
+ struct pollfd pfd[2];
+ sigset_t sigmask;
+ int sigfd;
+ enum {
+ POLLFD_SIGNAL = 0,
+ POLLFD_SOCKET
+ };
#ifdef HAVE_LIBSYSTEMD
if (!uuidd_cxt->no_sock) /* no_sock implies no_fork and no_pid */
#endif
{
+ static timer_t t_id;
+ struct itimerval timeout;
- signal(SIGALRM, terminate_intr);
- alarm(30);
+ memset(&timeout, 0, sizeof timeout);
+ timeout.it_value.tv_sec = 30;
+ if (setup_timer(&t_id, &timeout, &timeout_handler))
+ err(EXIT_FAILURE, _("cannot not setup timer"));
if (pidfile_path)
- fd_pidfile = create_pidfile(pidfile_path, uuidd_cxt->quiet);
-
+ fd_pidfile = create_pidfile(uuidd_cxt, pidfile_path, uuidd_cxt->quiet);
ret = call_daemon(socket_path, UUIDD_OP_GETPID, reply_buf,
sizeof(reply_buf), 0, NULL);
+ cancel_timer(&t_id);
if (ret > 0) {
if (!uuidd_cxt->quiet)
warnx(_("uuidd daemon is already running at pid %s"),
- reply_buf);
+ reply_buf);
exit(EXIT_FAILURE);
}
- alarm(0);
- s = create_socket(socket_path,
- (!uuidd_cxt->debug || !uuidd_cxt->no_fork),
- uuidd_cxt->quiet);
+ s = create_socket(uuidd_cxt, socket_path,
+ (!uuidd_cxt->debug || !uuidd_cxt->no_fork));
if (listen(s, SOMAXCONN) < 0) {
if (!uuidd_cxt->quiet)
warn(_("couldn't listen on unix socket %s"), socket_path);
@@ -342,12 +379,6 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
}
- signal(SIGHUP, terminate_intr);
- signal(SIGINT, terminate_intr);
- signal(SIGTERM, terminate_intr);
- signal(SIGALRM, terminate_intr);
- signal(SIGPIPE, SIG_IGN);
-
#ifdef HAVE_LIBSYSTEMD
if (uuidd_cxt->no_sock) {
const int ret = sd_listen_fds(0);
@@ -365,12 +396,38 @@ static void server_loop(const char *socket_path, const char *pidfile_path,
}
#endif
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGHUP);
+ sigaddset(&sigmask, SIGINT);
+ sigaddset(&sigmask, SIGTERM);
+ sigaddset(&sigmask, SIGALRM);
+ sigaddset(&sigmask, SIGPIPE);
+ /* Block signals so that they aren't handled according to their
+ * default dispositions */
+ sigprocmask(SIG_BLOCK, &sigmask, NULL);
+ if ((sigfd = signalfd(-1, &sigmask, 0)) < 0)
+ err(EXIT_FAILURE, _("cannot set signal handler"));
+
+ pfd[POLLFD_SIGNAL].fd = sigfd;
+ pfd[POLLFD_SOCKET].fd = s;
+ pfd[POLLFD_SIGNAL].events = pfd[POLLFD_SOCKET].events = POLLIN | POLLERR | POLLHUP;
+
while (1) {
+ ret = poll(pfd, ARRAY_SIZE(pfd), (uuidd_cxt->timeout == 0 ? -1 : uuidd_cxt->timeout * 1000));
+ if (ret < 0) {
+ if (errno == EAGAIN)
+ continue;
+ warn(_("poll failed"));
+ all_done(uuidd_cxt, EXIT_FAILURE);
+ }
+ if (ret == 0) /* truen when poll() times out */
+ all_done(uuidd_cxt, EXIT_SUCCESS);
+ if (pfd[POLLFD_SIGNAL].revents != 0)
+ handle_signal(uuidd_cxt, sigfd);
+ if (pfd[POLLFD_SOCKET].revents == 0)
+ continue;
fromlen = sizeof(from_addr);
- if (uuidd_cxt->timeout != 0)
- alarm(uuidd_cxt->timeout);
ns = accept(s, (struct sockaddr *) &from_addr, &fromlen);
- alarm(0);
if (ns < 0) {
if ((errno == EAGAIN) || (errno == EINTR))
continue;