From: dietmar@proxmox.com

* define signalfd header (missing in older glibc, i.e. on debian lenny)

* rename lxc_utils.h to util.h

* simple binary protocol implementaion for lxc_init daemon

* strdup_printf: I find that quite useful

* safe_read/safe_write/full_write: signal aware read/write

Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>

---
---
 src/lxc/utils.c |  220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/utils.h |   26 ++++++
 2 files changed, 246 insertions(+)

Index: lxc/src/lxc/utils.h
===================================================================
--- lxc.orig/src/lxc/utils.h
+++ lxc/src/lxc/utils.h
@@ -5,6 +5,7 @@
  *
  * Authors:
  * Daniel Lezcano <dlezcano at fr.ibm.com>
+ * Dietmar Maurer <dietmar at proxmox.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,6 +24,13 @@
 #ifndef _utils_h
 #define _utils_h
 
+#ifdef HAVE_SYS_SIGNALFD_H
+#include <sys/signalfd.h>
+#else
+extern int signalfd (int fd, const sigset_t *mask, int flags);
+#endif
+
+
 #define LXC_TTY_HANDLER(s) \
 	static struct sigaction lxc_tty_sa_##s;				\
 	static void tty_##s##_handler(int sig, siginfo_t *info, void *ctx) \
@@ -48,6 +56,24 @@
 		sigaction(s, &lxc_tty_sa_##s, NULL); \
 	} while (0)
 
+ssize_t safe_read (int fd, char *buf, size_t count);
+
+ssize_t safe_write (int fd, char *buf, size_t count);
+
+int full_write(int fd, char *buf, size_t len);
+
+char * pack_command (char *cmd, char *argv[], int *cmdlen);
+
+char ** unpack_command (char *data, int len, char **cmd);
+
+int lxc_exec_cmd (char *cmdsock, char *cmd, char *argv[], int *res);
+
+int lxc_exec_wait (char *cmdsock, int cmdid);
+
+int lxc_exec_kill (char *cmdsock, int cmdid, int signum);
+
+char *strdup_printf (const char *fmt, ...);
+
 #endif
 
 extern int lxc_copy_file(const char *src, const char *dst);
Index: lxc/src/lxc/utils.c
===================================================================
--- lxc.orig/src/lxc/utils.c
+++ lxc/src/lxc/utils.c
@@ -31,6 +31,8 @@
 #include <sys/mman.h>
 #include <sys/param.h>
 #include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <dirent.h>
 #include <fcntl.h>
 
@@ -289,3 +291,221 @@ extern int get_u16(ushort *val, const ch
 	return 0;
 }
 
+ssize_t safe_read(int fd, char *buf, size_t count)
+{
+	ssize_t n;
+
+	do {
+		n = read (fd, buf, count);
+	} while (n < 0 && errno == EINTR);
+
+	return n;
+}
+
+ssize_t safe_write(int fd, char *buf, size_t count)
+{
+	ssize_t n;
+
+	do {
+		n = write (fd, buf, count);
+	} while (n < 0 && errno == EINTR);
+
+	return n;
+}
+
+int full_write(int fd, char *buf, size_t len)
+{
+	size_t n;
+	size_t total;
+
+	total = 0;
+
+	while (len > 0) {
+	        n = safe_write(fd, buf, len);
+
+		if (n < 0)
+		        break;
+
+		buf += n;
+		total += n;
+		len -= n;
+	}
+
+	return total;
+}
+
+/*
+  binary message format:
+
+  int len;
+  str cmd
+  str args[];
+ */
+char *pack_command(char *cmd, char *argv[], int *cmdlen)
+{
+	int ind = 0;
+	int len = 1 + strlen (cmd);
+	while (argv[ind]) {
+		int arglen = strlen (argv[ind]);
+		if (arglen > 255) {
+			return NULL;
+		}
+		len += arglen + 1;
+		ind ++;
+	}
+
+	char *data = malloc (len + sizeof (int));
+	*((int *)data) = len;
+	char *p = data + sizeof (int);
+
+	int arglen = strlen (cmd);
+	*p++ = arglen;
+	strncpy (p, cmd, arglen);
+	p += arglen;
+
+	ind = 0;
+	while (argv[ind]) {
+		int arglen = strlen (argv[ind]);
+		*p++ = arglen;
+		strncpy (p, argv[ind], arglen);
+		p += arglen;
+		ind++;
+	}
+
+	if (cmdlen) *cmdlen = len + sizeof (int);
+	return data;
+}
+
+char **unpack_command(char *data, int len, char **cmd)
+{
+	char *p = data;
+	char *argv[255];
+	int argc = 0;
+
+	int arglen = *p++;
+	*cmd = strndup (p, arglen);
+	p += arglen;
+
+	while ((p - data) < len) {
+		arglen = *p++;
+		argv[argc] = strndup (p, arglen);
+		argc++;
+		p += arglen;
+	}
+	argv[argc] = NULL;
+
+	int size = sizeof (void *) * (argc + 1);
+	char **av = malloc (size);
+	memcpy (av, argv, size);
+
+	return av;
+}
+
+int lxc_exec_cmd(char *cmdsock, char *cmd, char *argv[], int *res)
+{
+	struct sockaddr_un addr;
+	int msglen = 0;
+	char *msg = pack_command (cmd, argv, &msglen);
+
+	int sock = socket (PF_UNIX, SOCK_STREAM, 0);
+	if (sock == -1) {
+		perror ("faild to create socket");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(struct sockaddr_un));
+
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, cmdsock, sizeof(addr.sun_path) - 1);
+
+	if (connect(sock, (struct sockaddr *) &addr,
+		    sizeof(struct sockaddr_un)) == -1) {
+		perror ("command socket bind failed");
+		return -1;
+	}
+
+	int n_read;
+	pid_t cmdid = 0;
+
+	if (safe_write (sock, msg, msglen) != msglen)  {
+		fprintf (stderr, "write failed\n");
+		return 1;
+	}
+
+	if ((n_read = read (sock, &cmdid, sizeof (cmdid))) != sizeof (cmdid)) {
+		fprintf (stderr, "exter failed\n");
+		return 1;
+	}
+
+	printf ("CMDID = %d\n", cmdid);
+
+	if (res) *res = cmdid;
+
+	return sock;
+}
+
+int lxc_exec_wait (char *cmdsock, int cmdid)
+{
+	char pidstr[24];
+	char *arg[] = {NULL, NULL};
+
+	sprintf (pidstr, "%d", cmdid);
+	arg[0] = pidstr;
+
+	int res;
+	int fd = lxc_exec_cmd (cmdsock, "wait", arg, &res);
+	close (fd);
+
+	return res;
+}
+
+int lxc_exec_kill(char *cmdsock, int cmdid, int signum)
+{
+	char pidstr[24];
+	char sigstr[24];
+	char *arg[] = {NULL, NULL, NULL};
+
+	sprintf (pidstr, "%d", cmdid);
+	arg[0] = pidstr;
+	sprintf (sigstr, "%d", signum);
+	arg[1] = sigstr;
+
+	int res;
+	int fd = lxc_exec_cmd (cmdsock, "kill", arg, &res);
+	close (fd);
+
+	return res;
+}
+
+/* code from the snprintf(3) manual page */
+char *strdup_printf(const char *fmt, ...)
+{
+	/* Guess we need no more than 64 bytes. */
+	int n, size = 64;
+	char *p, *np;
+	va_list ap;
+
+	if ((p = malloc (size)) == NULL)
+		return NULL;
+
+	while (1) {
+		/* Try to print in the allocated space. */
+		va_start(ap, fmt);
+		n = vsnprintf (p, size, fmt, ap);
+		va_end(ap);
+		/* If that worked, return the string. */
+		if (n > -1 && n < size)
+			return p;
+		/* Else try again with more space. */
+		if (n > -1)    /* glibc 2.1 */
+			size = n+1; /* precisely what is needed */
+		else           /* glibc 2.0 */
+			size *= 2;  /* twice the old size */
+		if ((np = realloc (p, size)) == NULL) {
+			free(p);
+			return NULL;
+		} else {
+			p = np;
+		}
+	}
+}



