Integration of UTS Namespace Testcases to LTP as submitted by <risrajak@linux.vnet.ibm.com>
diff --git a/README b/README
index 55b6dbf..777887f 100644
--- a/README
+++ b/README
@@ -78,6 +78,12 @@
 	that we found but haven't integrated into LTP yet.  Feel free to suggest
 	new snippets to be added, or take one of these and finish it off.
 
+testcases/kernel/containers/*
+	Contains all the testcases related to container functionality ( e.g: utsname etc..)
+	For further information on the each of the container functionality refer
+	the following file: testcases/kernel/containers/README
+
+
 Warning!
 --------
 Be careful with these tests!
diff --git a/runltp b/runltp
index d335de0..3a9d0d8 100755
--- a/runltp
+++ b/runltp
@@ -283,7 +283,8 @@
                      ${LTPROOT}/runtest/fsx ${LTPROOT}/runtest/dio \
                      ${LTPROOT}/runtest/mm ${LTPROOT}/runtest/ipc \
                      ${LTPROOT}/runtest/sched ${LTPROOT}/runtest/math \
-                     ${LTPROOT}/runtest/nptl ${LTPROOT}/runtest/pty
+                     ${LTPROOT}/runtest/nptl ${LTPROOT}/runtest/pty \
+                     ${LTPROOT}/runtest/containers
         do
             [ -a "$SCENFILES" ] || \
             {
diff --git a/runtest/containers b/runtest/containers
new file mode 100644
index 0000000..5665ec7
--- /dev/null
+++ b/runtest/containers
@@ -0,0 +1,2 @@
+#DESCRIPTION:Resource namespaces
+Containers	container_test.sh
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index 8362633..511849c 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = include fs io ipc mem pty sched security syscalls
+SUBDIRS = containers include fs io ipc mem pty sched security syscalls
 UCLINUX_SUBDIRS = syscalls
 
 all:
diff --git a/testcases/kernel/containers/Makefile b/testcases/kernel/containers/Makefile
new file mode 100644
index 0000000..32a2c70
--- /dev/null
+++ b/testcases/kernel/containers/Makefile
@@ -0,0 +1,14 @@
+SUBDIRS = libclone utsname
+
+all noltp noltp_check:
+	@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i $@; done
+
+install:
+	@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i install ; done
+	chmod ugo+x container_test.sh
+	ln -f container_test.sh ../../bin/container_test.sh
+
+clean:
+	@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i clean ; done
+
+
diff --git a/testcases/kernel/containers/README b/testcases/kernel/containers/README
new file mode 100644
index 0000000..cefc4c4
--- /dev/null
+++ b/testcases/kernel/containers/README
@@ -0,0 +1,12 @@
+CONTAINER TESTS AUTOMATION SUITE
+----------------------------
+
+The container test automation suite helps run the container functionality
+(e.g: utsname etc..) tests and report results. Please refer the following
+each functionality README file for detail:
+
+utsname/*
+	Contains all the testcases related to utsname tests.
+libclone/*
+	Contains the library API for clone() .
+
diff --git a/testcases/kernel/containers/container_test.sh b/testcases/kernel/containers/container_test.sh
new file mode 100755
index 0000000..a045286
--- /dev/null
+++ b/testcases/kernel/containers/container_test.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# This test performs capability tests for file operations.
+#
+# Copyright 2007 IBM
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+
+#check_utsns_enabled
+#if [ $? -eq 0 ]; then
+	echo "Running utsns tests."
+	runutstest.sh
+#else
+#	echo "Uts namespaces not enabled in kernel.  Not running utsns tests."
+#fi
+
+#check_pidns_enabled
+#if [ $? -eq 0 ]; then
+#	echo "Running pidns tests."
+#	runpidnstest.sh
+#else
+	#echo "Process id namespaces not enabled in kernel.  Not running pidns tests."
+#fi
+
+#check_userns_enabled
+#if [ $? -eq 0 ]; then
+	#echo "Running userns tests."
+#	userns_mounts unshare
+#	userns_mounts clone
+#	userns_sigio none
+#	userns_sigio unshare
+#	userns_sigio clone
+#	for i in `seq 1 4`; do
+#		userns_sigpending $i
+#	done
+#else
+	#echo "User namespaces not enabled in kernel.  Not running userns tests."
+#fi
diff --git a/testcases/kernel/containers/libclone/Makefile b/testcases/kernel/containers/libclone/Makefile
new file mode 100755
index 0000000..c03cf91
--- /dev/null
+++ b/testcases/kernel/containers/libclone/Makefile
@@ -0,0 +1,15 @@
+TARGET=libclone.a
+SRCS=$(wildcard *.c)
+OBJS=$(patsubst %.c,%.o,$(SRCS))
+
+all noltp : $(TARGET)
+
+$(TARGET): $(OBJS)
+	$(AR) -cr $@ $^
+
+clean:
+	rm -f $(TARGET) $(OBJS)
+
+noltp_check: noltp
+
+install:
diff --git a/testcases/kernel/containers/libclone/libclone.c b/testcases/kernel/containers/libclone/libclone.c
new file mode 100644
index 0000000..f555c84
--- /dev/null
+++ b/testcases/kernel/containers/libclone/libclone.c
@@ -0,0 +1,132 @@
+#include "libclone.h"
+
+/* Serge: should I be passing in strings for error messages? */
+
+int do_clone_tests(unsigned long clone_flags,
+			int(*fn1)(void *arg), void *arg1,
+			int(*fn2)(void *arg), void *arg2)
+{
+	int ret;
+	void *childstack, *stack = malloc(getpagesize());
+
+	if (!stack) {
+		perror("malloc");
+		return -1;
+	}
+
+	childstack = stack + getpagesize();
+
+	ret = clone(fn1, childstack, clone_flags | SIGCHLD, arg1);
+	if (ret == -1) {
+		perror("clone");
+		free(stack);
+		return -1;
+	}
+	if (fn2)
+		ret = fn2(arg2);
+	else
+		ret = 0;
+
+	return ret;
+}
+
+int do_unshare_tests(unsigned long clone_flags,
+			int (*fn1)(void *arg), void *arg1,
+			int (*fn2)(void *arg), void *arg2)
+{
+	int pid, ret = 0;
+	int retpipe[2];
+	char buf[2];
+
+	if (pipe(retpipe) == -1) {
+		perror("pipe");
+		return -1;
+	}
+	pid = fork();
+	if (pid == -1) {
+		perror("fork");
+		close(retpipe[0]);
+		close(retpipe[1]);
+		return -1;
+	}
+	if (pid == 0) {
+		close(retpipe[0]);
+		ret = syscall(SYS_unshare, clone_flags);
+		if (ret == -1) {
+			write(retpipe[1], "0", 2);
+			close(retpipe[1]);
+			perror("unshare");
+			exit(1);
+		} else
+			write(retpipe[1], "1", 2);
+		close(retpipe[1]);
+		ret = fn1(arg1);
+		exit(ret);
+	} else {
+		close(retpipe[1]);
+		read(retpipe[0], &buf, 2);
+		close(retpipe[0]);
+		if (*buf == '0')
+			return -1;
+		if (fn2)
+			ret = fn2(arg2);
+	}
+
+	return ret;
+}
+
+int do_plain_tests(int (*fn1)(void *arg), void *arg1,
+			int (*fn2)(void *arg), void *arg2)
+{
+	int ret = 0, pid;
+
+	pid = fork();
+	if (pid == -1) {
+		perror("fork");
+		return -1;
+	}
+	if (pid == 0)
+		return fn1(arg1);
+	if (fn2)
+		ret = fn2(arg2);
+	return ret;
+}
+
+int do_clone_unshare_test(int use_clone, unsigned long clone_flags,
+			int (*fn1)(void *arg), void *arg1)
+{
+	switch (use_clone) {
+	case T_NONE:
+		return do_plain_tests(fn1, arg1, NULL, NULL);
+	case T_CLONE:
+		return do_clone_tests(clone_flags, fn1, arg1, NULL, NULL);
+	case T_UNSHARE:
+		return do_unshare_tests(clone_flags, fn1, arg1, NULL, NULL);
+	default:
+		printf("%s: bad use_clone option: %d\n", __FUNCTION__,
+							use_clone);
+		return -1;
+	}
+}
+
+
+/*
+ * Run fn1 in a unshared environmnent, and fn2 in the original context
+ */
+int do_clone_unshare_tests(int use_clone, unsigned long clone_flags,
+			int (*fn1)(void *arg), void *arg1,
+			int (*fn2)(void *arg), void *arg2)
+{
+	switch (use_clone) {
+	case T_NONE:
+		return do_plain_tests(fn1, arg1, fn2, arg2);
+	case T_CLONE:
+		return do_clone_tests(clone_flags, fn1, arg1, fn2, arg2);
+	case T_UNSHARE:
+		return do_unshare_tests(clone_flags, fn1, arg1, fn2, arg2);
+	default:
+		printf("%s: bad use_clone option: %d\n", __FUNCTION__,
+							use_clone);
+		return -1;
+	}
+}
diff --git a/testcases/kernel/containers/libclone/libclone.h b/testcases/kernel/containers/libclone/libclone.h
new file mode 100644
index 0000000..9d3ce4a
--- /dev/null
+++ b/testcases/kernel/containers/libclone/libclone.h
@@ -0,0 +1,85 @@
+#ifndef __LIBCLONE_H
+#define __LIBCLONE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <libgen.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <signal.h>
+
+#define T_UNSHARE 0
+#define T_CLONE 1
+#define T_NONE 2
+
+#ifndef SYS_unshare
+#ifdef __NR_unshare
+#define SYS_unshare __NR_unshare
+#elif __i386__
+#define SYS_unshare 310
+#elif __ia64__
+#define SYS_unshare 1296
+#elif __x86_64__
+#define SYS_unshare 272
+#elif __s390x__
+#define SYS_unshare 303
+#elif __powerpc__
+#define SYS_unshare 282
+#else
+#error "unshare not supported on this architecure."
+#endif
+#endif
+
+#ifndef CLONE_NEWUTS
+#define CLONE_NEWUTS		0x04000000
+#endif
+
+#ifndef CLONE_NEWIPC
+#define CLONE_NEWIPC		0x08000000
+#endif
+
+#ifndef CLONE_NEWUSER
+#define CLONE_NEWUSER		0x10000000
+#endif
+
+#ifndef CLONE_NEWNET2
+#define CLONE_NEWNET2		0x20000000
+#endif
+
+#ifndef CLONE_NEWNET3
+#define CLONE_NEWNET3		0x40000000
+#endif
+
+#ifndef CLONE_NEWPID
+#define CLONE_NEWPID		0x80000000
+#endif
+
+/*
+ * Run fn1 in a unshared environmnent, and fn2 in the original context
+ * Fn2 may be NULL.
+ */
+
+int do_clone_tests(unsigned long clone_flags,
+			int(*fn1)(void *arg), void *arg1,
+			int(*fn2)(void *arg), void *arg2);
+
+int do_unshare_tests(unsigned long clone_flags,
+			int (*fn1)(void *arg), void *arg1,
+			int (*fn2)(void *arg), void *arg2);
+
+int do_fork_tests(int (*fn1)(void *arg), void *arg1,
+			int (*fn2)(void *arg), void *arg2);
+
+int do_clone_unshare_test(int use_clone, unsigned long clone_flags,
+			int (*fn1)(void *arg), void *arg1);
+
+int do_clone_unshare_tests(int use_clone, unsigned long clone_flags,
+			int (*fn1)(void *arg), void *arg1,
+			int (*fn2)(void *arg), void *arg2);
+
+#endif
diff --git a/testcases/kernel/containers/utsname/Makefile b/testcases/kernel/containers/utsname/Makefile
new file mode 100755
index 0000000..7a18a82
--- /dev/null
+++ b/testcases/kernel/containers/utsname/Makefile
@@ -0,0 +1,24 @@
+CC=gcc
+
+CFLAGS += -I../../../../include -I../libclone -Wall
+LDLIBS += -L../../../../lib -L../libclone ../libclone/libclone.a -lltp
+
+SRCS    = $(wildcard *.c)
+TARGETS = $(patsubst %.c,%,$(SRCS))
+NOLTP_TARGETS = $(patsubst %.c,%_noltp,$(SRCS))
+
+%_noltp : %.c
+	$(CC) -g -DNO_LTP -o $@ $< ../libclone/libclone.a
+
+all: $(TARGETS)
+
+noltp:  $(NOLTP_TARGETS)
+
+clean:
+	rm -f $(TARGETS) *.o $(NOLTP_TARGETS)
+
+install:
+	@set -e; for i in $(TARGETS) runutstest.sh check_utsns_enabled; do ln -f $$i ../../../bin/$$i ; chmod +x runutstest.sh ; done
+
+noltp_check: noltp
+	./runtests_noltp.sh
diff --git a/testcases/kernel/containers/utsname/README b/testcases/kernel/containers/utsname/README
new file mode 100644
index 0000000..bc97cd9
--- /dev/null
+++ b/testcases/kernel/containers/utsname/README
@@ -0,0 +1,33 @@
+This contains five tests for the uts namespace unsharing functionality.
+
+To enable this functionality, you currently must use a -mm kernel (see
+kernel.org). Then to run these tests, just type
+
+	sh runutstest.sh
+
+The tests are intended to do the following:
+
+test 1: check that after fork, two children see the same utsname
+	P1: A=gethostname
+	P2: B=gethostname
+	Ensure(A==B)
+test 2: check that after fork, two children are in the same utsname namespace.
+	P1: sethostname(newname); A=gethostname
+	P2: (wait); B=gethostname
+	Ensure (A==B)
+
+test 3: check that after unshare, processes are in different utsname namespaces.
+	P1: A=gethostname; unshare(utsname); sethostname(newname); C=gethostname
+	P2: B=gethostname; (wait); (wait); D=gethostname
+	Ensure (A==B && A==D && C!=D)
+
+test 4: similar to test 3, but other child changes hostname.
+	P1: A=gethostname; unshare(utsname); (wait); C=gethostname
+	P2: B=gethostname; (wait); sethostname(newname); D=gethostname
+	Ensure (A==B && A==C && C!=D)
+
+test 5: check that unsharing utsname without required permissions (CAP_SYS_AUDIT)
+	fails.
+	P1: A=gethostname; unshare(utsname) without suff. perms; (wait); C=gethostname
+	P2: B=gethostname; (wait); sethostname(newname); D=gethostname
+	Ensure (A==B==C==D) and state is ok.
diff --git a/testcases/kernel/containers/utsname/check_utsns_enabled.c b/testcases/kernel/containers/utsname/check_utsns_enabled.c
new file mode 100644
index 0000000..befa673
--- /dev/null
+++ b/testcases/kernel/containers/utsname/check_utsns_enabled.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2007 IBM
+ * Author: Serge Hallyn <serue@us.ibm.com>
+ *
+ * uts namespaces were introduced around 2.6.19.  Kernels before that,
+ * assume they are not enabled.  Kernels after that, check for -EINVAL
+ * when trying to use CLONE_NEWUTS.
+ */
+
+#include <sys/utsname.h>
+#include <sched.h>
+#include <stdio.h>
+#include "../libclone/libclone.h"
+#include "test.h"
+
+int dummy(void *v)
+{
+	return 0;
+}
+
+/*
+ * Not really expecting anyone to use this on a 2.6.19-rc kernel,
+ * else we may get some false positives here.
+ */
+#if 0
+int kernel_version_newenough()
+{
+	int ret;
+	struct utsname buf;
+	char *s;
+	int maj, min, micro;
+
+	ret = uname(&buf);
+	if (ret == -1) {
+		perror("uname");
+		return 0;
+	}
+	s = buf.release;
+	sscanf(s, "%d.%d.%d", &maj, &min, &micro);
+	if (maj < 2)
+		return 0;
+	if (min < 6)
+		return 0;
+	if (micro < 19)
+		return 0;
+	return 1;
+}
+#endif  /* Library is already provided by LTP*/
+int main()
+{
+	void *childstack, *stack;
+	int pid;
+
+	//if (!kernel_version_newenough())
+	if (tst_kvercmp(2,6,19) < 0)
+		return 1;
+	stack = malloc(getpagesize());
+	if (!stack) {
+		perror("malloc");
+		return 2;
+	}
+
+	childstack = stack + getpagesize();
+
+	pid = clone(dummy, childstack, CLONE_NEWUTS, NULL);
+
+	if (pid == -1)
+		return 3;
+	return 0;
+}
diff --git a/testcases/kernel/containers/utsname/runtests_noltp.sh b/testcases/kernel/containers/utsname/runtests_noltp.sh
new file mode 100755
index 0000000..5298666
--- /dev/null
+++ b/testcases/kernel/containers/utsname/runtests_noltp.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+exit_code=0
+echo "unshare tests"
+for i in `seq 1 5`; do
+	echo "test $i (unshare)"
+	./utstest_noltp unshare $i
+	if [ $? -ne 0 ]; then
+		exit_code=$?
+	fi
+done
+echo "clone tests"
+for i in `seq 1 5`; do
+	echo "test $i (clone)"
+	./utstest_noltp clone $i
+	if [ $? -ne 0 ]; then
+		exit_code=$?
+	fi
+done
+exit $exit_code
diff --git a/testcases/kernel/containers/utsname/runutstest.sh b/testcases/kernel/containers/utsname/runutstest.sh
new file mode 100755
index 0000000..dfa8304
--- /dev/null
+++ b/testcases/kernel/containers/utsname/runutstest.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+echo "unshare tests"
+for i in `seq 1 5`; do
+	echo "test $i (unshare)"
+	utstest unshare $i
+done
+echo "clone tests"
+for i in `seq 1 5`; do
+	echo "test $i (clone)"
+	utstest clone $i
+done
diff --git a/testcases/kernel/containers/utsname/utstest.c b/testcases/kernel/containers/utsname/utstest.c
new file mode 100644
index 0000000..73f96bc
--- /dev/null
+++ b/testcases/kernel/containers/utsname/utstest.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2007 IBM
+ * Author: Serge Hallyn <serue@us.ibm.com>
+ *
+ * test1:
+	P1: A=gethostname
+	P2: B=gethostname
+	Ensure(A==B)
+
+ * test2:
+	P1: sethostname(A);
+	P2: (wait); B=gethostname
+	Ensure (A==B)
+
+ * test3:
+	P1: A=gethostname; unshare(utsname); sethostname(newname); C=gethostname
+	P2: B=gethostname; (wait); (wait); D=gethostname
+	Ensure (A==B && A==D && C!=D)
+
+ * test4:
+	P1: A=gethostname; unshare(utsname); (wait); C=gethostname
+	P2: B=gethostname; (wait); sethostname(newname); D=gethostname
+	Ensure (A==B && A==C && C!=D)
+
+ * test5:
+	P1: drop_privs(); unshare(utsname); (wait); C=gethostname
+	P2: (wait); sethostname(B); D=gethostname
+	Ensure (B==C==D) and state is ok.
+ *
+ */
+
+#define _GNU_SOURCE 1
+#include <sys/wait.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#ifndef NO_LTP
+#include <test.h>
+#include <libclone.h>
+#else
+#include "../libclone/libclone.h"
+#endif
+
+char *TCID = "uts_namespace";
+int TST_TOTAL=1;
+
+#ifdef NO_LTP
+#define TFAIL "FAILURE: "
+#define TPASS "PASS: "
+#define tst_resm(x, format, arg...) printf("%s:" format, x, ## arg)
+#define tst_exit() exit(1)
+#endif
+
+int drop_root()
+{
+	int ret;
+	ret = setresuid(1000, 1000, 1000);
+	if (ret) {
+		perror("setresuid");
+		exit(4);
+	}
+	return 1;
+}
+
+int p1fd[2], p2fd[2];
+pid_t cpid;
+
+#define HLEN 100
+#define NAME1 "serge1"
+#define NAME2 "serge2"
+
+void picknewhostname(char *orig, char *new)
+{
+	memset(new, 0, HLEN);
+	if (strcmp(orig, NAME1) == 0)
+		strcpy(new, NAME2);
+	else
+		strcpy(new, NAME1);
+}
+
+void zeroize(char *s)
+{
+	memset(s, 0, HLEN);
+}
+
+char *tsttype;
+int P1(void *vtest)
+{
+	char hostname[HLEN], newhostname[HLEN], rhostname[HLEN];
+	int err;
+	int len;
+	int testnum;
+
+	testnum = atoi((char *)vtest);
+
+	close(p1fd[1]);
+	close(p2fd[0]);
+
+	switch(testnum) {
+	case 1:
+		gethostname(hostname, HLEN);
+		zeroize(rhostname);
+		len = read(p1fd[0], rhostname, HLEN);
+		if (strcmp(hostname, rhostname) == 0) {
+			tst_resm(TPASS, "test 1 (%s): success\n", tsttype);
+			tst_exit();
+		}
+		tst_resm(TFAIL, "test 1 (%s): hostname 1 %s, hostname 2 %s\n",
+			tsttype, hostname, rhostname);
+		tst_exit();
+	case 2:
+		gethostname(hostname, HLEN);
+		picknewhostname(hostname, newhostname);
+		err = sethostname(newhostname, strlen(newhostname));
+		write(p2fd[1], "1", 1);
+		if (err == -1) {
+			tst_resm(TFAIL, "test 2 (%s): failed to sethostname",
+					tsttype);
+			tst_exit();
+		}
+		zeroize(rhostname);
+		len = read(p1fd[0], rhostname, HLEN);
+		if (strcmp(newhostname, rhostname) == 0) {
+			tst_resm(TPASS, "test 2 (%s): success\n",
+					tsttype);
+			tst_exit();
+		}
+		tst_resm(TFAIL, "test 2 (%s) hostname 1 %s, hostname 2 %s\n",
+				tsttype, newhostname, rhostname);
+		tst_exit();
+	case 3:
+		gethostname(hostname, HLEN);
+		picknewhostname(hostname, newhostname);
+		err = sethostname(newhostname, strlen(newhostname));
+		write(p2fd[1], "1", 1);
+		if (err == -1) {
+			tst_resm(TFAIL, "test 3 (%s): failed to sethostname",
+						tsttype);
+			tst_exit();
+		}
+
+		zeroize(rhostname);
+		len = read(p1fd[0], rhostname, HLEN);
+		if (strcmp(newhostname, rhostname) == 0) {
+			tst_resm(TFAIL, "test 3 (%s): hostname 1 %s, hostname 2 %s, these should have been different\n",
+					tsttype, newhostname, rhostname);
+			tst_exit();
+		}
+		if (strcmp(hostname, rhostname) == 0) {
+			tst_resm(TPASS, "test 3 (%s): success\n", tsttype);
+			tst_exit();
+		}
+		tst_resm(TFAIL, "test 3 (%s): hostname 1 %s, hostname 2 %s, should have been same\n",
+			tsttype, hostname, rhostname);
+		tst_exit();
+
+	case 4:
+		gethostname(hostname, HLEN);
+		write(p2fd[1], "1", 1); /* tell p2 to go ahead and sethostname */
+		zeroize(rhostname);
+		len = read(p1fd[0], rhostname, HLEN);
+		gethostname(newhostname, HLEN);
+		if (strcmp(hostname, newhostname) != 0) {
+			tst_resm(TFAIL, "test 4 (%s): hostname 1 %s, hostname 2 %s, should be same\n",
+				tsttype, hostname, newhostname);
+			tst_exit();
+		}
+		if (strcmp(hostname, rhostname) == 0) {
+			tst_resm(TFAIL, "test 4 (%s): hostname 1 %s, hostname 2 %s, should be different",
+				tsttype, hostname, rhostname);
+			tst_exit();
+		}
+		tst_resm(TPASS, "test 4 (%s): successful\n", tsttype);
+		tst_exit();
+	case 5:
+		write(p2fd[1], "1", 1); /* tell p2 to go ahead and sethostname */
+		zeroize(rhostname);
+		len = read(p1fd[0], rhostname, HLEN);
+		gethostname(newhostname, HLEN);
+		if (strcmp(rhostname, newhostname) != 0) {
+			tst_resm(TFAIL, "test 5 (%s): hostnames %s and %s should be same\n",
+				tsttype, rhostname, newhostname);
+			tst_exit();
+		}
+		tst_resm(TPASS, "test 5 (%s): successful", tsttype);
+		tst_exit();
+	default:
+		break;
+	}
+	return -1;
+}
+
+int P2(void *vtest)
+{
+	char hostname[HLEN], newhostname[HLEN];
+	int len;
+	int testnum;
+
+	testnum = atoi((char *)vtest);
+
+	close(p1fd[0]);
+	close(p2fd[1]);
+
+	switch(testnum) {
+	case 1:
+		gethostname(hostname, HLEN);
+		write(p1fd[1], hostname, strlen(hostname));
+		break;
+	case 2:
+	case 3:
+		len = 0;
+		while (!len) {
+			len = read(p2fd[0], hostname, 1);
+		}
+		gethostname(hostname, HLEN);
+		write(p1fd[1], hostname, strlen(hostname));
+		break;
+	case 4:
+	case 5:
+		len = 0;
+		while (!len) {
+			len = read(p2fd[0], hostname, 1);
+		}
+		if (hostname[0] == '0') {
+			tst_resm(TPASS, "P2: P1 claims error\n");
+			tst_exit();
+			exit(0);
+		}
+		gethostname(hostname, HLEN);
+		picknewhostname(hostname, newhostname);
+		sethostname(newhostname, strlen(newhostname));
+		write(p1fd[1], newhostname, strlen(newhostname));
+		break;
+	default:
+		tst_resm(TFAIL, "undefined test: %d\n", testnum);
+		break;
+	}
+	tst_exit();
+	return 0;
+}
+
+#define UNSHARESTR "unshare"
+#define CLONESTR "clone"
+int main(int argc, char *argv[])
+{
+	int r, pid, use_clone = T_UNSHARE;
+	int testnum;
+	void *vtest;
+
+	if (argc != 3) {
+		tst_resm(TFAIL, "Usage: %s <clone|unshare> <testnum>\n", argv[0]);
+		tst_resm(TFAIL, " where clone or unshare specifies unshare method,");
+		tst_resm(TFAIL, " and testnum is between 1 and 5 inclusive\n");
+		exit(2);
+	}
+	if (pipe(p1fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
+	if (pipe(p2fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
+
+	tsttype = UNSHARESTR;
+	if (strcmp(argv[1], "clone") == 0) {
+		use_clone = T_CLONE;
+		tsttype = CLONESTR;
+	}
+
+	testnum = atoi(argv[2]);
+
+	vtest = (void *)argv[2];
+	switch(testnum) {
+	case 1:
+	case 2: r = do_clone_unshare_tests(T_NONE, 0,
+					P1, vtest, P2, vtest);
+		break;
+	case 3:
+	case 4:
+		r = do_clone_unshare_tests(use_clone, CLONE_NEWUTS,
+					P1, vtest, P2, vtest);
+		break;
+	case 5:
+		pid = fork();
+		if (pid == -1) {
+			perror("fork");
+			exit(2);
+		}
+		if (pid == 0) {
+			if (!drop_root()) {
+				tst_resm(TFAIL, "failed to drop root.\n");
+				tst_exit();
+				exit(1);
+			}
+			r = do_clone_unshare_test(use_clone, CLONE_NEWUTS,
+					P1, vtest);
+			write(p2fd[1], "0", 1); /* don't let p2 hang */
+			exit(0);
+		} else {
+			P2(vtest);
+		}
+		break;
+	default:
+		tst_resm(TFAIL, "testnum should be between 1 and 5 inclusive.\n");
+		break;
+	}
+
+	tst_exit();
+}
diff --git a/testscripts/test_containers.sh b/testscripts/test_containers.sh
new file mode 100755
index 0000000..bc0cfaf
--- /dev/null
+++ b/testscripts/test_containers.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+#
+# Copyright 2007 IBM
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# test_containers.sh - Run the containers test suite.
+
+# Must be root to run the containers testsuite
+if [ $UID != 0 ]
+then
+        echo "FAILED: Must be root to execute this script"
+        exit 1
+fi
+
+# set the LTPROOT directory
+cd `dirname $0`
+LTPROOT=${PWD}
+echo $LTPROOT | grep testscripts > /dev/null 2>&1
+if [ $? -eq 0 ]
+then
+	cd ..
+	LTPROOT=${PWD}
+fi
+
+# set the PATH to include testcase/bin
+
+export PATH=$PATH:/usr/sbin:$LTPROOT/testcases/bin
+export LTPBIN=$LTPROOT/testcases/bin
+
+# We will store the logfiles in $LTPROOT/results, so make sure
+# it exists.
+if [ ! -d $LTPROOT/results ]
+then
+	mkdir $LTPROOT/results
+fi
+
+# Check the role and mode testsuite is being executed under.
+echo "Running the containers testsuite..."
+
+$LTPROOT/pan/pan -S -a $LTPROOT/results/containers -n ltp-containers -l $LTPROOT/results/containers.logfile -o $LTPROOT/results/containers.outfile -p -f $LTPROOT/runtest/containers
+
+echo "Done."
+exit 0