[CRIU] [PATCH] systemd support
Andrew Vagin
avagin at parallels.com
Tue Dec 10 19:20:49 PST 2013
pls, write description what this patch does.
On Tue, Dec 10, 2013 at 12:12:56PM -0800, Shawn Landden wrote:
> v2: spelling
> ---
> Makefile | 3 +
> Makefile.crtools | 1 +
> Makefile.inc | 1 +
> cr-service.c | 73 ++++----
> criu.service | 5 +
> criu.socket | 8 +
> sd-daemon.c | 521 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> sd-daemon.h | 282 ++++++++++++++++++++++++++++++
> 8 files changed, 862 insertions(+), 32 deletions(-)
> create mode 100644 criu.service
> create mode 100644 criu.socket
> create mode 100644 sd-daemon.c
> create mode 100644 sd-daemon.h
>
> diff --git a/Makefile b/Makefile
> index cd312e7..02282f4 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 criu.socket $(DESTDIR)$(SYSTEMDUNITDIR)
> + $(Q) install -m 644 criu.service $(DESTDIR)$(SYSTEMDUNITDIR)
>
> install-man:
> $(Q) $(MAKE) -C Documentation install
> diff --git a/Makefile.crtools b/Makefile.crtools
> index 71e9d1c..18140fd 100644
> --- a/Makefile.crtools
> +++ b/Makefile.crtools
> @@ -57,6 +57,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 23b4d9e..87a267a 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 a82ef9e..3b9cb02 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;
> +
> + server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
> + if (server_fd == -1) {
> + pr_perror("Can't initialize service socket.");
> + goto err;
> + }
>
> - memset(&server_addr, 0, sizeof(server_addr));
> - memset(&client_addr, 0, sizeof(client_addr));
> - server_addr.sun_family = AF_LOCAL;
> + memset(&server_addr, 0, sizeof(server_addr));
> + memset(&client_addr, 0, sizeof(client_addr));
> + server_addr.sun_family = AF_LOCAL;
>
> - if (opts.addr == NULL)
> - opts.addr = CR_DEFAULT_SERVICE_ADDRESS;
> + if (opts.addr == NULL)
> + opts.addr = CR_DEFAULT_SERVICE_ADDRESS;
>
> - strcpy(server_addr.sun_path, opts.addr);
> + strcpy(server_addr.sun_path, opts.addr);
>
> - server_addr_len = strlen(server_addr.sun_path)
> - + sizeof(server_addr.sun_family);
> - client_addr_len = sizeof(client_addr);
> + server_addr_len = strlen(server_addr.sun_path)
> + + sizeof(server_addr.sun_family);
> + client_addr_len = sizeof(client_addr);
>
> - unlink(server_addr.sun_path);
> + unlink(server_addr.sun_path);
>
> - if (bind(server_fd, (struct sockaddr *) &server_addr,
> - server_addr_len) == -1) {
> - pr_perror("Can't bind.");
> - goto err;
> - }
> + if (bind(server_fd, (struct sockaddr *) &server_addr,
> + server_addr_len) == -1) {
> + pr_perror("Can't bind.");
> + goto err;
> + }
>
> - pr_info("The service socket is bound to %s\n", server_addr.sun_path);
> + pr_info("The service socket is bound to %s\n", server_addr.sun_path);
>
> - /* 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;
> - }
> + /* 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 (listen(server_fd, 16) == -1) {
> + pr_perror("Can't listen for socket connections.");
> + goto err;
> + }
> }
>
> if (daemon_mode) {
> diff --git a/criu.service b/criu.service
> new file mode 100644
> index 0000000..803ce46
> --- /dev/null
> +++ b/criu.service
> @@ -0,0 +1,5 @@
> +[Unit]
> +Description=Checkpoint Restore in Userspace daemon
> +
> +[Service]
> +ExecStart=/usr/sbin/criu service
> diff --git a/criu.socket b/criu.socket
> new file mode 100644
> index 0000000..7ccf7b4
> --- /dev/null
> +++ b/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 0000000..2bf506e
> --- /dev/null
> +++ b/sd-daemon.c
> @@ -0,0 +1,521 @@
> +#define SD_DAEMON_DISABLE_MQ
> +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
> +
> +/***
> + 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 <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <fcntl.h>
> +#include <netinet/in.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <stddef.h>
> +#include <limits.h>
> +
> +#if defined(__linux__) && !defined(SD_DAEMON_DISABLE_MQ)
> +# include <mqueue.h>
> +#endif
> +
> +#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
> +}
> +
> +_sd_export_ int sd_is_fifo(int fd, const char *path) {
> + struct stat st_fd;
> +
> + if (fd < 0)
> + return -EINVAL;
> +
> + if (fstat(fd, &st_fd) < 0)
> + return -errno;
> +
> + if (!S_ISFIFO(st_fd.st_mode))
> + return 0;
> +
> + if (path) {
> + struct stat 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;
> +}
> +
> +_sd_export_ int sd_is_special(int fd, const char *path) {
> + struct stat st_fd;
> +
> + if (fd < 0)
> + return -EINVAL;
> +
> + if (fstat(fd, &st_fd) < 0)
> + return -errno;
> +
> + if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
> + return 0;
> +
> + if (path) {
> + struct stat st_path;
> +
> + if (stat(path, &st_path) < 0) {
> +
> + if (errno == ENOENT || errno == ENOTDIR)
> + return 0;
> +
> + return -errno;
> + }
> +
> + if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
> + return
> + st_path.st_dev == st_fd.st_dev &&
> + st_path.st_ino == st_fd.st_ino;
> + else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
> + return st_path.st_rdev == st_fd.st_rdev;
> + else
> + return 0;
> + }
> +
> + 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;
> +};
> +
> +_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
> + int r;
> +
> + if (family < 0)
> + return -EINVAL;
> +
> + r = sd_is_socket_internal(fd, type, listening);
> + if (r <= 0)
> + return r;
> +
> + if (family > 0) {
> + union sockaddr_union sockaddr = {};
> + socklen_t 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;
> +}
> +
> +_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
> + union sockaddr_union sockaddr = {};
> + socklen_t l = sizeof(sockaddr);
> + int r;
> +
> + if (family != 0 && family != AF_INET && family != AF_INET6)
> + return -EINVAL;
> +
> + r = sd_is_socket_internal(fd, type, listening);
> + if (r <= 0)
> + return r;
> +
> + 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;
> +}
> +
> +_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
> + union sockaddr_union sockaddr = {};
> + socklen_t l = sizeof(sockaddr);
> + int r;
> +
> + r = sd_is_socket_internal(fd, type, listening);
> + if (r <= 0)
> + return r;
> +
> + 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 == offsetof(struct sockaddr_un, sun_path);
> +
> + if (path[0])
> + /* Normal path socket */
> + return
> + (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
> + memcmp(path, sockaddr.un.sun_path, length+1) == 0;
> + else
> + /* Abstract namespace socket */
> + return
> + (l == offsetof(struct sockaddr_un, sun_path) + length) &&
> + memcmp(path, sockaddr.un.sun_path, length) == 0;
> + }
> +
> + return 1;
> +}
> +
> +_sd_export_ int sd_is_mq(int fd, const char *path) {
> +#if !defined(__linux__) || defined(SD_DAEMON_DISABLE_MQ)
> + return 0;
> +#else
> + struct mq_attr attr;
> +
> + if (fd < 0)
> + return -EINVAL;
> +
> + if (mq_getattr(fd, &attr) < 0)
> + return -errno;
> +
> + if (path) {
> + char fpath[PATH_MAX];
> + struct stat a, b;
> +
> + if (path[0] != '/')
> + return -EINVAL;
> +
> + if (fstat(fd, &a) < 0)
> + return -errno;
> +
> + strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
> + fpath[sizeof(fpath)-1] = 0;
> +
> + if (stat(fpath, &b) < 0)
> + return -errno;
> +
> + if (a.st_dev != b.st_dev ||
> + a.st_ino != b.st_ino)
> + return 0;
> + }
> +
> + return 1;
> +#endif
> +}
> +
> +_sd_export_ int sd_notify(int unset_environment, const char *state) {
> +#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;
> + const char *e;
> +
> + if (!state) {
> + r = -EINVAL;
> + goto finish;
> + }
> +
> + e = getenv("NOTIFY_SOCKET");
> + if (!e)
> + return 0;
> +
> + /* Must be an abstract socket, or an absolute path */
> + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
> + r = -EINVAL;
> + goto finish;
> + }
> +
> + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
> + if (fd < 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(&msghdr, 0, sizeof(msghdr));
> + msghdr.msg_name = &sockaddr;
> + msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + 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;
> +
> + 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
> +}
> +
> +_sd_export_ 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
> +}
> +
> +_sd_export_ int sd_booted(void) {
> +#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
> + return 0;
> +#else
> + struct stat st;
> +
> + /* We test whether the runtime unit file directory has been
> + * created. This takes place in mount-setup.c, so is
> + * guaranteed to happen very early during boot. */
> +
> + if (lstat("/run/systemd/system/", &st) < 0)
> + return 0;
> +
> + return !!S_ISDIR(st.st_mode);
> +#endif
> +}
> diff --git a/sd-daemon.h b/sd-daemon.h
> new file mode 100644
> index 0000000..daa3f4c
> --- /dev/null
> +++ b/sd-daemon.h
> @@ -0,0 +1,282 @@
> +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
> +
> +#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 <sys/types.h>
> +#include <inttypes.h>
> +
> +#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.
> +*/
> +
> +#ifndef _sd_printf_attr_
> +# if __GNUC__ >= 4
> +# define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
> +# else
> +# define _sd_printf_attr_(a,b)
> +# endif
> +#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);
> +
> +/*
> + 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);
> +
> +/*
> + Helper call for identifying a passed file descriptor. Returns 1 if
> + the file descriptor is a special character device on 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 special character.
> + Returns a negative errno style error code on failure.
> +
> + See sd_is_special(3) for more information.
> +*/
> +int sd_is_special(int fd, const char *path);
> +
> +/*
> + 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);
> +
> +/*
> + 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);
> +
> +/*
> + 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);
> +
> +/*
> + Helper call for identifying a passed file descriptor. Returns 1 if
> + the file descriptor is a POSIX Message Queue of the specified name,
> + 0 otherwise. If path is NULL a message queue name check is not
> + done. Returns a negative errno style error code on failure.
> +*/
> +int sd_is_mq(int fd, const char *path);
> +
> +/*
> + Informs systemd about changed daemon state. This takes a number of
> + newline separated 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 signaling 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"
> +
> + WATCHDOG=1 Tells systemd to update the watchdog timestamp.
> + Services using this feature should do this in
> + regular intervals. A watchdog framework can use the
> + timestamps to detect failed services.
> +
> + Daemons can choose to send additional variables. However, it is
> + recommended 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);
> +
> +/*
> + 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);
> +
> +/*
> + 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 user and system services.
> +
> + See sd_booted(3) for more information.
> +*/
> +int sd_booted(void);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
> --
> 1.8.5.1
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://lists.openvz.org/mailman/listinfo/criu
More information about the CRIU
mailing list