diff --git a/Makefile b/Makefile index cd312e7ff..c9a60420e 100644 --- a/Makefile +++ b/Makefile @@ -232,6 +232,9 @@ install: $(PROGRAM) install-man $(E) " INSTALL " $(PROGRAM) $(Q) mkdir -p $(DESTDIR)$(SBINDIR) $(Q) install -m 755 $(PROGRAM) $(DESTDIR)$(SBINDIR) + $(Q) mkdir -p $(DESTDIR)$(SYSTEMDUNITDIR) + $(Q) install -m 644 scripts/sd/criu.socket $(DESTDIR)$(SYSTEMDUNITDIR) + $(Q) install -m 644 scripts/sd/criu.service $(DESTDIR)$(SYSTEMDUNITDIR) install-man: $(Q) $(MAKE) -C Documentation install diff --git a/Makefile.crtools b/Makefile.crtools index 3030ce9aa..3f746893f 100644 --- a/Makefile.crtools +++ b/Makefile.crtools @@ -56,6 +56,7 @@ obj-y += string.o obj-y += sigframe.o obj-y += arch/$(ARCH)/vdso.o obj-y += cr-service.o +obj-y += sd-daemon.o ifneq ($(MAKECMDGOALS),clean) incdeps := y diff --git a/Makefile.inc b/Makefile.inc index 23b4d9e97..87a267a37 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -14,3 +14,4 @@ export E Q PREFIX := /usr/local SBINDIR := $(PREFIX)/sbin MANDIR := $(PREFIX)/share/man +SYSTEMDUNITDIR := $(PREFIX)/lib/systemd/system/ diff --git a/cr-service.c b/cr-service.c index a82ef9edd..88ae18311 100644 --- a/cr-service.c +++ b/cr-service.c @@ -19,6 +19,7 @@ #include "log.h" #include "pstree.h" #include "cr-service.h" +#include "sd-daemon.h" unsigned int service_sk_ino = -1; @@ -332,53 +333,61 @@ static int restore_sigchld_handler() int cr_service(bool daemon_mode) { - int server_fd = -1; + int server_fd = -1, n; int child_pid; - struct sockaddr_un server_addr; struct sockaddr_un client_addr; - - socklen_t server_addr_len; socklen_t client_addr_len; - server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0); - if (server_fd == -1) { - pr_perror("Can't initialize service socket."); + n = sd_listen_fds(0); + if (n > 1) { + pr_perror("Too many file descriptors (%d) recieved.", n); goto err; - } + } else if (n == 1) + server_fd = SD_LISTEN_FDS_START + 0; + else { + struct sockaddr_un server_addr; + socklen_t server_addr_len; - memset(&server_addr, 0, sizeof(server_addr)); - memset(&client_addr, 0, sizeof(client_addr)); - server_addr.sun_family = AF_LOCAL; + server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0); + if (server_fd == -1) { + pr_perror("Can't initialize service socket."); + goto err; + } - if (opts.addr == NULL) - opts.addr = CR_DEFAULT_SERVICE_ADDRESS; + memset(&server_addr, 0, sizeof(server_addr)); + memset(&client_addr, 0, sizeof(client_addr)); + server_addr.sun_family = AF_LOCAL; - strcpy(server_addr.sun_path, opts.addr); + if (opts.addr == NULL) + opts.addr = CR_DEFAULT_SERVICE_ADDRESS; - server_addr_len = strlen(server_addr.sun_path) - + sizeof(server_addr.sun_family); - client_addr_len = sizeof(client_addr); + strcpy(server_addr.sun_path, opts.addr); - unlink(server_addr.sun_path); + server_addr_len = strlen(server_addr.sun_path) + + sizeof(server_addr.sun_family); + client_addr_len = sizeof(client_addr); - if (bind(server_fd, (struct sockaddr *) &server_addr, - server_addr_len) == -1) { - pr_perror("Can't bind."); - goto err; - } + unlink(server_addr.sun_path); - pr_info("The service socket is bound to %s\n", server_addr.sun_path); + if (bind(server_fd, (struct sockaddr *) &server_addr, + server_addr_len) == -1) { + pr_perror("Can't bind."); + goto err; + } - /* change service socket permissions, so anyone can connect to it */ - if (chmod(server_addr.sun_path, 0666)) { - pr_perror("Can't change permissions of the service socket."); - goto err; - } + pr_info("The service socket is bound to %s\n", server_addr.sun_path); - if (listen(server_fd, 16) == -1) { - pr_perror("Can't listen for socket connections."); - goto err; + /* change service socket permissions, so anyone can connect to it */ + if (chmod(server_addr.sun_path, 0666)) { + pr_perror("Can't change permissions of the service socket."); + goto err; + } + + if (listen(server_fd, 16) == -1) { + pr_perror("Can't listen for socket connections."); + goto err; + } } if (daemon_mode) { diff --git a/scripts/sd/criu.service b/scripts/sd/criu.service new file mode 100644 index 000000000..803ce4695 --- /dev/null +++ b/scripts/sd/criu.service @@ -0,0 +1,5 @@ +[Unit] +Description=Checkpoint Restore in Userspace daemon + +[Service] +ExecStart=/usr/sbin/criu service diff --git a/scripts/sd/criu.socket b/scripts/sd/criu.socket new file mode 100644 index 000000000..7ccf7b407 --- /dev/null +++ b/scripts/sd/criu.socket @@ -0,0 +1,8 @@ +[Unit] +Description=Checkpoint Restore in Userspace socket + +[Socket] +ListenSequentialPacket=/var/run/criu-service.socket + +[Install] +WantedBy=sockets.target diff --git a/sd-daemon.c b/sd-daemon.c new file mode 100644 index 000000000..653fbf575 --- /dev/null +++ b/sd-daemon.c @@ -0,0 +1,132 @@ +/* stripped down version */ +/*** + 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 "sd-daemon.h" + +#if (__GNUC__ >= 4) +# ifdef SD_EXPORT_SYMBOLS +/* Export symbols */ +# define _sd_export_ __attribute__ ((visibility("default"))) +# else +/* Don't export the symbols */ +# define _sd_export_ __attribute__ ((visibility("hidden"))) +# endif +#else +# define _sd_export_ +#endif + +_sd_export_ 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; + + e = getenv("LISTEN_PID"); + if (!e) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno > 0) { + r = -errno; + goto finish; + } + + if (!p || p == e || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + /* Is this for us? */ + if (getpid() != (pid_t) l) { + r = 0; + goto finish; + } + + e = getenv("LISTEN_FDS"); + if (!e) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno > 0) { + r = -errno; + goto finish; + } + + if (!p || p == e || *p) { + r = -EINVAL; + goto finish; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { + int flags; + + flags = fcntl(fd, F_GETFD); + if (flags < 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 +} + diff --git a/sd-daemon.h b/sd-daemon.h new file mode 100644 index 000000000..f6f2959c4 --- /dev/null +++ b/sd-daemon.h @@ -0,0 +1,91 @@ +/* stripped down version */ + +#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. +***/ + +#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/systemd/plain/src/systemd/sd-daemon.h + http://cgit.freedesktop.org/systemd/systemd/plain/src/libsystemd-daemon/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(3) for more information. +*/ + +/* 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); + +#ifdef __cplusplus +} +#endif + +#endif