[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