Handle the stop command. The stop command waits for the peer to
disconnect, that means the peer has exited, so it is safe to
return to the user control. By this way, we ensure a stop command
followed by a start or a destroy won't fail with a race condition
because the start command is not yet finised.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Michel Normand <normand@fr.ibm.com>
---
 src/lxc/commands.c |    3 ++
 src/lxc/commands.h |    1 
 src/lxc/stop.c     |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 64 insertions(+), 1 deletion(-)

Index: lxc/src/lxc/commands.c
===================================================================
--- lxc.orig/src/lxc/commands.c
+++ lxc/src/lxc/commands.c
@@ -95,6 +95,8 @@ out_close:
 extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info);
 extern int lxc_console_callback(int fd, struct lxc_request *request,
 			struct lxc_handler *handler);
+extern int lxc_stop_callback(int fd, struct lxc_request *request,
+			struct lxc_handler *handler);
 
 static int trigger_command(int fd, struct lxc_request *request,
 			struct lxc_handler *handler)
@@ -104,6 +106,7 @@ static int trigger_command(int fd, struc
 
 	callback cb[LXC_COMMAND_MAX] = {
 		[LXC_COMMAND_TTY] = lxc_console_callback,
+		[LXC_COMMAND_STOP] = lxc_stop_callback,
 	};
 
 	if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
Index: lxc/src/lxc/commands.h
===================================================================
--- lxc.orig/src/lxc/commands.h
+++ lxc/src/lxc/commands.h
@@ -25,6 +25,7 @@
 
 enum {
 	LXC_COMMAND_TTY,
+	LXC_COMMAND_STOP,
 	LXC_COMMAND_MAX,
 };
 
Index: lxc/src/lxc/stop.c
===================================================================
--- lxc.orig/src/lxc/stop.c
+++ lxc/src/lxc/stop.c
@@ -33,12 +33,13 @@
 
 #include <lxc/lxc.h>
 #include <lxc/log.h>
+#include "commands.h"
 
 lxc_log_define(lxc_stop, lxc);
 
 #define MAXPIDLEN 20
 
-int lxc_stop(const char *name)
+int __lxc_stop(const char *name)
 {
 	char init[MAXPATHLEN];
 	char val[MAXPIDLEN];
@@ -73,3 +74,61 @@ out_close:
 	close(fd);
 	return ret;
 }
+
+int lxc_stop(const char *name)
+{
+	struct lxc_command command = {
+		.request = { .type = LXC_COMMAND_STOP },
+	};
+
+	int ret;
+
+	ret = lxc_command(name, &command);
+	if (ret < 0) {
+		ERROR("failed to send command");
+		return -1;
+	}
+
+	/* we do not expect any answer, because we wait for the connection to be
+	 * closed
+	 */
+	if (ret > 0) {
+		ERROR("stop request rejected for '%s': %s",
+			name, strerror(-command.answer.ret));
+		return -1;
+	}
+
+	INFO("'%s' has stopped", name);
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------------
+ * functions used by lxc-start mainloop
+ * to handle above command request.
+ *--------------------------------------------------------------------------*/
+extern int lxc_stop_callback(int fd, struct lxc_request *request,
+			struct lxc_handler *handler)
+{
+	struct lxc_answer answer;
+	int ret;
+
+	answer.ret = kill(handler->pid, SIGKILL);
+	if (!answer.ret)
+		return 0;
+
+	ret = send(fd, &answer, sizeof(answer), 0);
+	if (ret < 0) {
+		WARN("failed to send answer to the peer");
+		goto out;
+	}
+
+	if (ret != sizeof(answer)) {
+		ERROR("partial answer sent");
+		goto out;
+	}
+
+out:
+	return -1;
+}
+



