test.sh: Fix ROD redirection && callers

The ROD could not detect failures when the output was redirected into a
file since the redirection was handled in the caller.

For example doing:

ROD echo a > /proc/cpus

Would have worked just fine since the $@ in ROD function would contain
only 'echo a'.

Moreover doing:

ROD false > tmpfile

Would end up writing the error message to the tmpfile instead of the
stdout.

For this reasons the ROD has been changed to take special char \> as
redirection operator. The only difference is that the > in the ROD
command must be prefixed with \ so that it's passed along with the file
to the ROD function. The $@ there is split on '>' and the redirection is
done inside ROD function which fixes the errors described above.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
Acked-by: Alexey Kodanev <alexey.kodanev@oracle.com>
diff --git a/doc/test-writing-guidelines.txt b/doc/test-writing-guidelines.txt
index 0c0909a..1f260cb 100644
--- a/doc/test-writing-guidelines.txt
+++ b/doc/test-writing-guidelines.txt
@@ -1249,6 +1249,24 @@
 fi
 -------------------------------------------------------------------------------
 
+WARNING: Keep in mind that output redirection (to a file) happens in the
+         caller rather than in the ROD function and cannot be checked for
+         write errors by the ROD function.
+
+As a matter of a fact doing +ROD echo a > /proc/cpuinfo+ would work just fine
+since the 'ROD' function will only get the +echo a+ part that will run just
+fine.
+
+[source,sh]
+-------------------------------------------------------------------------------
+# Redirect output to a file with ROD
+ROD echo foo \> bar
+-------------------------------------------------------------------------------
+
+Note the '>' is escaped with '\', this causes that the '>' and filename are
+passed to the 'ROD' function as parameters and the 'ROD' function contains
+code to split '$@' on '>' and redirects the output to the file.
+
 .tst_fs_has_free
 [source,sh]
 -------------------------------------------------------------------------------
diff --git a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh
index 2b990eb..df2cbfc 100755
--- a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh
+++ b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh
@@ -48,7 +48,7 @@
 
     tst_resm TINFO "Attaching task $pid to $path"
 
-    ROD echo "$pid" > "$path/tasks"
+    ROD echo "$pid" \> "$path/tasks"
 
     for task in $(cat "$path/tasks"); do
         if [ "$task" -ne "$pid" ]; then
@@ -69,8 +69,8 @@
     # cpuset.cpus and cpuset.mems must be initialized with suitable value
     # before any pids are attached
     if [ "$subsystem" == "cpuset" ]; then
-        ROD cat "$mount_point/cpuset.cpus" > "$path/cpuset.cpus"
-        ROD cat "$mount_point/cpuset.mems" > "$path/cpuset.mems"
+        ROD cat "$mount_point/cpuset.cpus" \> "$path/cpuset.cpus"
+        ROD cat "$mount_point/cpuset.mems" \> "$path/cpuset.mems"
     fi
 }
 
diff --git a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh
index b2d8e22..006798a 100755
--- a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh
+++ b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh
@@ -124,7 +124,7 @@
 
     ROD rmdir "$start_path/ltp_1/a"
 
-    ROD echo "$pid" > "$start_path/tasks"
+    ROD echo "$pid" \> "$start_path/tasks"
 }
 
 # Group cannot be moved outside of hierarchy
@@ -182,7 +182,7 @@
         return
     fi
 
-    ROD echo "$notify" > "$start_path/ltp_1/notify_on_release"
+    ROD echo "$notify" \> "$start_path/ltp_1/notify_on_release"
 
     tst_resm TPASS "Set $start_path/ltp_1/notify_on_release to $value"
 }
diff --git a/testcases/kernel/controllers/pids/pids.sh b/testcases/kernel/controllers/pids/pids.sh
index 068ff1f..e7600b3 100755
--- a/testcases/kernel/controllers/pids/pids.sh
+++ b/testcases/kernel/controllers/pids/pids.sh
@@ -109,7 +109,7 @@
 {
 	tmp=$((max - 1))
 	tst_resm TINFO "limit the number of pid to $max"
-	ROD echo $max > $testpath/pids.max
+	ROD echo $max \> $testpath/pids.max
 
 	start_pids_tasks2 $tmp
 
@@ -130,7 +130,7 @@
 {
 	lim=$((max + 2))
 	tst_resm TINFO "limit the number of avalaible pid to $lim"
-	ROD echo $lim > $testpath/pids.max
+	ROD echo $lim \> $testpath/pids.max
 
 	start_pids_tasks2 $max
 
@@ -149,7 +149,7 @@
 case4()
 {
 	tst_resm TINFO "limit the number of avalaible pid to 0"
-	ROD echo 0 > $testpath/pids.max
+	ROD echo 0 \> $testpath/pids.max
 
 	start_pids_tasks2 $max
 
diff --git a/testcases/lib/test.sh b/testcases/lib/test.sh
index 074be74..eeaf0b6 100644
--- a/testcases/lib/test.sh
+++ b/testcases/lib/test.sh
@@ -214,7 +214,35 @@
 
 ROD()
 {
-	$@
+	local cmd
+	local arg
+	local file
+	local flag
+
+	for arg; do
+		file="${arg#\>}"
+		if [ "$file" != "$arg" ]; then
+			flag=1
+			if [ -n "$file" ]; then
+				break
+			fi
+			continue
+		fi
+
+		if [ -n "$flag" ]; then
+			file="$arg"
+			break
+		fi
+
+		cmd="$cmd $arg"
+	done
+
+	if [ -n "$flag" ]; then
+		$cmd > $file
+	else
+		$@
+	fi
+
 	if [ $? -ne 0 ]; then
 		tst_brkm TBROK "$@ failed"
 	fi
diff --git a/testcases/network/nfs/nfs_stress/nfs03 b/testcases/network/nfs/nfs_stress/nfs03
index 952162d..03ad056 100755
--- a/testcases/network/nfs/nfs_stress/nfs03
+++ b/testcases/network/nfs/nfs_stress/nfs03
@@ -46,7 +46,7 @@
 	for j in $(seq 0 $DIR_NUM); do
 		cd dir$j
 		for k in $(seq 0 $FILE_NUM); do
-			ROD >file$j$k
+			ROD \>file$j$k
 		done
 		cd ..
 	done