[cgmanager-devel] [PATCH RFC] implement getTasks and getTasksScm

Serge Hallyn serge.hallyn at ubuntu.com
Thu Jan 16 00:10:37 UTC 2014


(I was going to push this to git head, but given this is an
extension of the API wanted to send it out for review.)

getTasks returns the tasks in a given cgroup as an array of ints.

getTasksScm sends the result over the passed-in unix fd.  It first
sends the # pids, then sends each pid as a separate SCM_CRED so as
to convert the pids to the client's pidns.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 access_checks.c                   |  99 ++++++++++++++++
 access_checks.h                   |   2 +
 cgmanager-proxy.c                 | 236 ++++++++++++++++++++++++++++++++------
 cgmanager.c                       | 147 ++++++++++++++++++++++++
 configure.ac                      |   2 +
 fs.c                              |  41 +++++++
 fs.h                              |   1 +
 org.linuxcontainers.cgmanager.xml |  11 ++
 tests/test15.sh                   |  24 ++++
 9 files changed, 531 insertions(+), 32 deletions(-)
 create mode 100755 tests/test15.sh

diff --git a/access_checks.c b/access_checks.c
index 85545df..f6f7eea 100644
--- a/access_checks.c
+++ b/access_checks.c
@@ -78,6 +78,105 @@ bool get_nih_io_creds(NihIo *io, struct ucred *ucred)
 	return true;
 }
 
+int send_creds(int sock, struct ucred cred)
+{
+	struct msghdr msg = { 0 };
+	struct iovec iov;
+	struct cmsghdr *cmsg;
+	char cmsgbuf[CMSG_SPACE(sizeof(cred))];
+	char buf[1];
+	buf[0] = 'p';
+
+	msg.msg_control = cmsgbuf;
+	msg.msg_controllen = sizeof(cmsgbuf);
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_CREDENTIALS;
+	memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+
+	iov.iov_base = buf;
+	iov.iov_len = sizeof(buf);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	if (sendmsg(sock, &msg, 0) < 0) {
+		perror("sendmsg");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Get a pid passed in a SCM_CREDENTIAL over a unix socket
+ * @sock: the socket fd.
+ * Credentials are invalid of *p == 1.
+ * Note - this is a synchronous version.  We use it only in the proxy to wait
+ * on the server, since there is no sense not hanging in that case.
+ */
+void get_scm_creds_sync(int sock, uid_t *u, gid_t *g, pid_t *p)
+{
+        struct msghdr msg = { 0 };
+        struct iovec iov;
+        struct cmsghdr *cmsg;
+	struct ucred cred;
+        char cmsgbuf[CMSG_SPACE(sizeof(cred))];
+        char buf[1];
+	int ret, tries=0;
+	int optval = 1;
+
+	cred.pid = -1;
+	cred.uid = -1;
+	cred.gid = -1;
+
+	if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+		nih_error("Failed to set passcred: %s", strerror(errno));
+		goto out;
+	}
+	buf[0] = '1';
+	if (write(sock, buf, 1) != 1) {
+		nih_error("Failed to start write on scm fd: %s", strerror(errno));
+		goto out;
+	}
+
+        msg.msg_name = NULL;
+        msg.msg_namelen = 0;
+        msg.msg_control = cmsgbuf;
+        msg.msg_controllen = sizeof(cmsgbuf);
+
+        iov.iov_base = buf;
+        iov.iov_len = sizeof(buf);
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+
+	// retry logic is not ideal, especially as we are not
+	// threaded.  Sleep at most 1 second waiting for the client
+	// to send us the scm_cred
+	ret = recvmsg(sock, &msg, 0);
+	if (ret < 0) {
+		nih_error("Failed to receive scm_cred: %s",
+			  strerror(errno));
+		goto out;
+	}
+
+        cmsg = CMSG_FIRSTHDR(&msg);
+
+        if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
+            cmsg->cmsg_level == SOL_SOCKET &&
+            cmsg->cmsg_type == SCM_CREDENTIALS) {
+		memcpy(&cred, CMSG_DATA(cmsg), sizeof(cred));
+        }
+out:
+	*u = cred.uid;
+	*g = cred.gid;
+	*p = cred.pid;
+        return;
+}
+
 int send_pid(int sock, int pid)
 {
 	struct msghdr msg = { 0 };
diff --git a/access_checks.h b/access_checks.h
index c5505f3..00ab303 100644
--- a/access_checks.h
+++ b/access_checks.h
@@ -25,6 +25,8 @@
  */
 
 bool get_nih_io_creds(NihIo *io, struct ucred *ucred);
+int send_creds(int sock, struct ucred cred);
+void get_scm_creds_sync(int sock, uid_t *u, gid_t *g, pid_t *p);
 bool is_same_pidns(int pid);
 bool is_same_userns(int pid);
 bool may_move_pid(pid_t r, uid_t r_uid, pid_t v);
diff --git a/cgmanager-proxy.c b/cgmanager-proxy.c
index f1fe554..484dd52 100644
--- a/cgmanager-proxy.c
+++ b/cgmanager-proxy.c
@@ -117,38 +117,6 @@ unsigned long mypidns;
 bool setns_user_supported = false;
 unsigned long myuserns;
 
-int send_creds(int sock, struct ucred cred)
-{
-	struct msghdr msg = { 0 };
-	struct iovec iov;
-	struct cmsghdr *cmsg;
-	char cmsgbuf[CMSG_SPACE(sizeof(cred))];
-	char buf[1];
-	buf[0] = 'p';
-
-	msg.msg_control = cmsgbuf;
-	msg.msg_controllen = sizeof(cmsgbuf);
-
-	cmsg = CMSG_FIRSTHDR(&msg);
-	cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
-	cmsg->cmsg_level = SOL_SOCKET;
-	cmsg->cmsg_type = SCM_CREDENTIALS;
-	memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
-
-	msg.msg_name = NULL;
-	msg.msg_namelen = 0;
-
-	iov.iov_base = buf;
-	iov.iov_len = sizeof(buf);
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-
-	if (sendmsg(sock, &msg, 0) < 0) {
-		perror("sendmsg");
-		return -1;
-	}
-	return 0;
-}
 
 void send_dummy_msg(DBusConnection *conn)
 {
@@ -1492,6 +1460,210 @@ int cgmanager_remove (void *data, NihDBusMessage *message,
 	return ret;
 }
 
+/* 
+ * This is one of the dbus callbacks.
+ * Caller requests the number of tasks in @cgroup in @controller
+ * returns nrpids, or -1 on error.
+ */
+int get_tasks_main (void *parent, const char *controller, char *cgroup, struct ucred ucred, int32_t **pids)
+{
+	char buf[1];
+	DBusMessage *message = NULL;
+	DBusMessageIter iter;
+	int sv[2], ret = -1, optval = 1;
+	dbus_uint32_t serial;;
+	uid_t u; gid_t g;
+	uint32_t nrpids;
+	pid_t tmp;
+	int i;
+
+	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
+		nih_error("Error creating socketpair: %s", strerror(errno));
+		return -1;
+	}
+	if (setsockopt(sv[1], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+		nih_error("setsockopt: %s", strerror(errno));
+		goto out;
+	}
+	if (setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+		nih_error("setsockopt: %s", strerror(errno));
+		goto out;
+	}
+
+	message = dbus_message_new_method_call(dbus_bus_get_unique_name(server_conn),
+			"/org/linuxcontainers/cgmanager",
+			"org.linuxcontainers.cgmanager0_0", "getTasksScm");
+
+	dbus_message_iter_init_append(message, &iter);
+        if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &controller)) {
+                nih_error_raise_no_memory ();
+                goto out;
+        }
+        if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &cgroup)) {
+                nih_error_raise_no_memory ();
+                goto out;
+        }
+	if (! dbus_message_iter_append_basic (&iter, DBUS_TYPE_UNIX_FD, &sv[1])) {
+		nih_error_raise_no_memory ();
+		goto out;
+	}
+
+	if (!dbus_connection_send(server_conn, message, &serial)) {
+		nih_error("failed to send dbus message");
+		goto out;
+	}
+	dbus_connection_flush(server_conn);
+	if (message) {
+		dbus_message_unref(message);
+		message = NULL;
+	}
+
+	if (read(sv[0], buf, 1) != 1) {
+		nih_error("Error getting reply from server over socketpair");
+		goto out;
+	}
+	if (send_creds(sv[0], ucred)) {
+		nih_error("Error sending pid over SCM_CREDENTIAL");
+		goto out;
+	}
+	if (read(sv[0], &nrpids, sizeof(uint32_t)) != sizeof(uint32_t))
+		goto out;
+	if (nrpids == 0) {
+		ret = 0;
+		goto out;
+	}
+
+	*pids = nih_alloc(parent, nrpids * sizeof(uint32_t));
+	for (i=0; i<nrpids; i++) {
+		get_scm_creds_sync(sv[0], &u, &g, &tmp);
+		if (tmp == -1) {
+			nih_error("Failed getting pid from server");
+			goto out;
+		}
+		(*pids)[i] = tmp;
+	}
+	ret = nrpids;
+out:
+	close(sv[0]);
+	close(sv[1]);
+	if (message)
+		dbus_message_unref(message);
+	return ret;
+}
+
+void get_tasks_scm_reader (struct scm_sock_data *data,
+		NihIo *io, const char *buf, size_t len)
+{
+	struct ucred ucred, pcred;;
+	int i, ret;
+	int32_t *pids, nrpids;
+
+	if (!get_nih_io_creds(io, &ucred)) {
+		nih_error("failed to read ucred");
+		goto out;
+	}
+	nih_info (_("getTasksScm: Client fd is: %d (pid=%d, uid=%d, gid=%d)"),
+		  data->fd, ucred.pid, ucred.uid, ucred.gid);
+
+	ret = get_tasks_main(data, data->controller, data->cgroup, ucred, &pids);
+	if (ret < 0) {
+		nih_error("Error getting nrtasks for %s:%s for pid %d",
+			data->controller, data->cgroup, ucred.pid);
+		nih_io_shutdown(io);
+		return;
+	}
+	nrpids = ret;
+	if (write(data->fd, &nrpids, sizeof(int32_t)) != sizeof(int32_t)) {
+		nih_error("get_tasks_scm: Error writing final result to client");
+		goto out;
+	}
+
+	pcred.uid = 0; pcred.gid = 0;
+	for (i=0; i<ret; i++) {
+		pcred.pid = pids[i];
+		if (send_creds(data->fd, pcred)) {
+			nih_error("get_tasks_scm: error writing pids back to client");
+			goto out;
+		}
+	}
+out:
+	nih_io_shutdown(io);
+}
+int cgmanager_get_tasks_scm (void *data, NihDBusMessage *message,
+		 const char *controller, char *cgroup, int sockfd)
+{
+	struct scm_sock_data *d;
+        char buf[1];
+	int optval = -1;
+
+	if (setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			     "Failed to set passcred: %s", strerror(errno));
+		return -1;
+	}
+	d = nih_alloc(NULL, sizeof(*d));
+	if (!d) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_NO_MEMORY,
+			"Out of memory");
+		return -1;
+	}
+	memset(d, 0, sizeof(*d));
+	d->controller = nih_strdup(d, controller);
+	d->cgroup = nih_strdup(d, cgroup);
+	d->fd = sockfd;
+
+	if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
+		(NihIoReader)get_tasks_scm_reader,
+		(NihIoCloseHandler) scm_sock_close,
+		 NULL, d)) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			"Failed to queue scm message: %s", strerror(errno));
+		return -1;
+	}
+	buf[0] = '1';
+	if (write(sockfd, buf, 1) != 1) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			"Failed to start write on scm fd: %s", strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+int cgmanager_get_tasks (void *data, NihDBusMessage *message,
+			 const char *controller, char *cgroup, int32_t **pids, size_t *nrpids)
+{
+	int fd = 0, ret;
+	struct ucred ucred;
+	socklen_t len;
+	int32_t *tmp;
+
+	if (message == NULL) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			"message was null");
+		return -1;
+	}
+
+	if (!dbus_connection_get_socket(message->connection, &fd)) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+		                             "Could  not get client socket.");
+		return -1;
+	}
+
+	len = sizeof(struct ucred);
+	NIH_MUST (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) != -1);
+
+	nih_info (_("getTasks: Client fd is: %d (pid=%d, uid=%d, gid=%d)"),
+		  fd, ucred.pid, ucred.uid, ucred.gid);
+
+	ret = get_tasks_main(message, controller, cgroup, ucred, &tmp);
+	if (ret >= 0) {
+		*nrpids = ret;
+		*pids = tmp;
+		ret = 0;
+	} else
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+		                             "invalid request");
+	return ret;
+}
 
 int cgmanager_ping (void *data, NihDBusMessage *message, int junk)
 {
diff --git a/cgmanager.c b/cgmanager.c
index d2fbb04..38ecdf9 100644
--- a/cgmanager.c
+++ b/cgmanager.c
@@ -1395,6 +1395,153 @@ int cgmanager_remove (void *data, NihDBusMessage *message,
 	return ret;
 }
 
+/* 
+ * This is one of the dbus callbacks.
+ * Caller requests the number of tasks in @cgroup in @controller
+ * returns nrpids, or -1 on error.
+ */
+int get_tasks_main (void *parent, const char *controller, char *cgroup, struct ucred ucred, int32_t **pids)
+{
+	char path[MAXPATHLEN];
+	const char *key = "tasks";
+
+	if (!cgroup || ! *cgroup)  // nothing to do
+		return 0;
+	if (!compute_pid_cgroup(ucred.pid, controller, cgroup, path)) {
+		nih_error("Could not determine the requested cgroup");
+		return -1;
+	}
+
+	/* Check access rights to the cgroup directory */
+	if (!may_access(ucred.pid, ucred.uid, ucred.gid, path, O_RDONLY)) {
+		nih_error("Pid %d may not access %s\n", (int)ucred.pid, path);
+		return -1;
+	}
+
+	/* append the filename */
+	if (strlen(path) + strlen(key) + 2 > MAXPATHLEN) {
+		nih_error("filename too long for cgroup %s key %s", path, key);
+		return -1;
+	}
+
+	strncat(path, "/", MAXPATHLEN-1);
+	strncat(path, key, MAXPATHLEN-1);
+
+	return file_read_pids(parent, path, pids);
+}
+
+void get_tasks_scm_reader (struct scm_sock_data *data,
+		NihIo *io, const char *buf, size_t len)
+{
+	struct ucred ucred, pcred;
+	int i, ret;
+	int32_t *pids, nrpids;
+
+	if (!get_nih_io_creds(io, &ucred)) {
+		nih_error("failed to read ucred");
+		goto out;
+	}
+	nih_info (_("getTasksScm: Client fd is: %d (pid=%d, uid=%d, gid=%d)"),
+		  data->fd, ucred.pid, ucred.uid, ucred.gid);
+
+	ret = get_tasks_main(data, data->controller, data->cgroup, ucred, &pids);
+	if (ret < 0) {
+		nih_error("Error getting nrtasks for %s:%s for pid %d",
+			data->controller, data->cgroup, ucred.pid);
+		nih_io_shutdown(io);
+		return;
+	}
+	nrpids = ret;
+	if (write(data->fd, &nrpids, sizeof(int32_t)) != sizeof(int32_t)) {
+		nih_error("get_tasks_scm: Error writing final result to client");
+		goto out;
+	}
+	pcred.uid = 0; pcred.gid = 0;
+	for (i=0; i<ret; i++) {
+		pcred.pid = pids[i];
+		if (send_creds(data->fd, pcred)) {
+			nih_error("get_tasks_scm: error writing pids back to client");
+			goto out;
+		}
+	}
+out:
+	nih_io_shutdown(io);
+}
+int cgmanager_get_tasks_scm (void *data, NihDBusMessage *message,
+		 const char *controller, char *cgroup, int sockfd)
+{
+	struct scm_sock_data *d;
+        char buf[1];
+	int optval = -1;
+
+	if (setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			     "Failed to set passcred: %s", strerror(errno));
+		return -1;
+	}
+	d = nih_alloc(NULL, sizeof(*d));
+	if (!d) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_NO_MEMORY,
+			"Out of memory");
+		return -1;
+	}
+	memset(d, 0, sizeof(*d));
+	d->controller = nih_strdup(d, controller);
+	d->cgroup = nih_strdup(d, cgroup);
+	d->fd = sockfd;
+
+	if (!nih_io_reopen(NULL, sockfd, NIH_IO_MESSAGE,
+		(NihIoReader)get_tasks_scm_reader,
+		(NihIoCloseHandler) scm_sock_close,
+		 NULL, d)) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			"Failed to queue scm message: %s", strerror(errno));
+		return -1;
+	}
+	buf[0] = '1';
+	if (write(sockfd, buf, 1) != 1) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			"Failed to start write on scm fd: %s", strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+int cgmanager_get_tasks (void *data, NihDBusMessage *message,
+			 const char *controller, char *cgroup, int32_t **pids, size_t *nrpids)
+{
+	int fd = 0, ret;
+	struct ucred ucred;
+	socklen_t len;
+	int32_t *tmp;
+
+	if (message == NULL) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+			"message was null");
+		return -1;
+	}
+
+	if (!dbus_connection_get_socket(message->connection, &fd)) {
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+		                             "Could  not get client socket.");
+		return -1;
+	}
+
+	len = sizeof(struct ucred);
+	NIH_MUST (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) != -1);
+
+	nih_info (_("getTasks: Client fd is: %d (pid=%d, uid=%d, gid=%d)"),
+		  fd, ucred.pid, ucred.uid, ucred.gid);
+
+	ret = get_tasks_main(message, controller, cgroup, ucred, &tmp);
+	if (ret >= 0) {
+		*nrpids = ret;
+		*pids = tmp;
+		ret = 0;
+	} else
+		nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
+		                             "invalid request");
+	return ret;
+}
 
 static dbus_bool_t allow_user(DBusConnection *connection, unsigned long uid, void *data)
 {
diff --git a/configure.ac b/configure.ac
index 31c1e3d..4ce8152 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,6 +12,8 @@ AM_INIT_AUTOMAKE
 LT_INIT
 AC_PROG_CC
 
+AC_PROG_CC_C99
+
 AC_PATH_PROG([NIH_DBUS_TOOL], [nih-dbus-tool])
 
 PKG_CHECK_MODULES([NIH], [libnih >= 1.0.2])
diff --git a/fs.c b/fs.c
index 7494766..1408016 100644
--- a/fs.c
+++ b/fs.c
@@ -469,6 +469,47 @@ out:
 }
 
 /*
+ * file_read_pids:
+ *
+ * @parent: parent which will be given a reference to the returned string
+ * (to allow the returned value to be freed automatically when @parent is
+ * freed).
+ * @path: Full path to file to read.
+ *
+ * Read specified file and return the pids it contains.  The file is
+ * expected to contain only a set of newline-separated int32_ts.
+ *
+ * Returns: Number of pids read, which are placed into the newly allocated
+ * pids array (passed in).
+ */
+int file_read_pids(void *parent, const char *path, int32_t **pids)
+{
+	int nrpids = 0, pid;
+	FILE *fin = fopen(path, "r");
+
+	*pids = NULL;
+	if (!fin) {
+		nih_error("Error opening %s: %s", path, strerror(errno));
+		return -1;
+	}
+
+	while (fscanf(fin, "%d", &pid) == 1) {
+		int32_t *tmp;
+		if (!(tmp = nih_realloc(*pids, parent, (nrpids+1)*sizeof(int32_t)))) {
+			if (*pids)
+				nih_free(*pids);
+			pids = NULL;
+			goto out;
+		}
+		*pids = tmp;
+		(*pids)[nrpids++] = (int32_t) pid;
+	}
+out:
+	fclose(fin);
+	return nrpids;
+}
+
+/*
  * get_pid_creds: get the real uid and gid of @pid from
  * /proc/$$/status
  * (XXX should we use euid here?)
diff --git a/fs.h b/fs.h
index 46ffe54..16c288a 100644
--- a/fs.h
+++ b/fs.h
@@ -29,6 +29,7 @@ bool compute_pid_cgroup(pid_t pid, const char *controller, const char *cgroup, c
 bool may_access(pid_t pid, uid_t uid, gid_t gid, const char *path, int mode);
 void get_pid_creds(pid_t pid, uid_t *uid, gid_t *gid);
 char *file_read_string(void *parent, const char *path);
+int file_read_pids(void *parent, const char *path, int32_t **pids);
 void get_pid_creds(pid_t pid, uid_t *uid, gid_t *gid);
 const char *get_controller_path(const char *controller);
 uid_t hostuid_to_ns(uid_t uid, pid_t pid);
diff --git a/org.linuxcontainers.cgmanager.xml b/org.linuxcontainers.cgmanager.xml
index 42485d1..a684bf2 100644
--- a/org.linuxcontainers.cgmanager.xml
+++ b/org.linuxcontainers.cgmanager.xml
@@ -120,6 +120,17 @@
       <arg name="recursive" type="i" direction="in" />
       <arg name="existed" type="i" direction="out" />
     </method>
+    <method name="getTasksScm">
+      <arg name="controller" type="s" direction="in" />
+      <arg name="cgroup" type="s" direction="in" />
+      <arg name="sockfd" type="h" direction="in" />
+      <!-- nrtasks + pids as scm creds return value comes over sockfd -->
+    </method>
+    <method name="getTasks">
+      <arg name="controller" type="s" direction="in" />
+      <arg name="cgroup" type="s" direction="in" />
+      <arg name="output" type="ai" direction="out" />
+    </method>
     <!-- still to add: low priority,
 	 Remove
 	 Prune (remove all empty decendents)
diff --git a/tests/test15.sh b/tests/test15.sh
new file mode 100755
index 0000000..a693e33
--- /dev/null
+++ b/tests/test15.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+ret=0
+echo "Test 14 (nrtasks)"
+
+dbus-send --print-reply --address=unix:path=/sys/fs/cgroup/cgmanager/sock --type=method_call /org/linuxcontainers/cgmanager org.linuxcontainers.cgmanager0_0.Create string:'memory' string:"xxx/c" > /dev/null 2>&1
+
+sleep 200 &
+pid=$!
+
+dbus-send --print-reply --address=unix:path=/sys/fs/cgroup/cgmanager/sock --type=method_call /org/linuxcontainers/cgmanager org.linuxcontainers.cgmanager0_0.movePid string:'memory' string:"xxx/c" int32:$pid > /dev/null 2>&1
+
+result=`dbus-send --print-reply=literal --address=unix:path=/sys/fs/cgroup/cgmanager/sock --type=method_call /org/linuxcontainers/cgmanager org.linuxcontainers.cgmanager0_0.getTasks string:'memory' string:"xxx/c" | awk '/int32/ { print $2 }'`
+
+if [ "$result" != "$pid" ]; then
+	echo "result is $result not $pid"
+	ret=1
+fi
+
+kill -9 $pid 2>&1 > /dev/null
+
+dbus-send --print-reply --address=unix:path=/sys/fs/cgroup/cgmanager/sock --type=method_call /org/linuxcontainers/cgmanager org.linuxcontainers.cgmanager0_0.Remove string:'memory' string:"xxx/c" int32:0 > /dev/null 2>&1
+
+exit $ret
-- 
1.8.5.2



More information about the cgmanager-devel mailing list