--- /dev/null
+#!/bin/bash
+
+readonly TESTUSER=owner
+readonly TEST_SUBSESSIONS=("TestSuite_sub1" "TestSuite_sub2" "TestSuite_sub3" "TestSuite_sub4" "TestSuite_sub5")
+readonly GROUP=users
+
+# Setting it to `true` makes the script more verbose, making debugging easier.
+VERBOSE=
+
+# Default value of waiting time (in seconds) for the completion of the
+# add/remove subsession operation.
+DELAYVAL=0.1
+
+# Default value of the number of times the waiting loop for the completion of
+# the add/remove subsession operation is repeated.
+# 5 x 0.1s = 0.5s which should be enough even on a moderately loaded system,
+# but if it's not, one can always increase it with the `-m` parameter.
+MAXTRIES=5
+
+verbose_echo()
+{
+ if [ "$VERBOSE" = "true" ]; then
+ echo "$1"
+ fi
+}
+
+create_test_users()
+{
+ for subsession in "${TEST_SUBSESSIONS[@]}"; do
+ echo "Creating test user: $subsession"
+ # Make a direct request to the server for adding a subsession.
+ busctl call -- org.tizen.sessiond /org/tizen/sessiond org.tizen.sessiond.subsession.Manager AddUser "is" "$userid" "$subsession"
+
+ # Return from the DBus call does not necessarily mean the completion of
+ # the AddUser operation. Since we're not listening to the AddUserCompletion
+ # signal here, the easiest way is to poll and check for the existence of
+ # the subsession directory. `sessiond` guarantees atomicity by copying
+ # subsession files and subdirectories to a temporary directory and
+ # renaming it after the copying operation is completed.
+ delay=0
+ created=
+ subsession_dir="$homedir/subsession/$subsession/apps_rw"
+ while [ $delay -lt $MAXTRIES ]
+ do
+ if [ -d "$subsession_dir" ]; then
+ created=true
+ break
+ fi
+ ((delay=delay+1))
+ sleep "$DELAYVAL"
+ done
+
+ if [ "$created" != "true" ]; then
+ echo "Creating user $subsession failed. Bailing out!"
+ exit 1
+ fi
+ done
+}
+
+remove_test_users()
+{
+ for subsession in "${TEST_SUBSESSIONS[@]}"; do
+ echo "Removing user: $subsession"
+ # Make a direct request to the server for removing a subsession.
+ busctl call -- org.tizen.sessiond /org/tizen/sessiond org.tizen.sessiond.subsession.Manager RemoveUser "is" "$userid" "$subsession"
+
+ # See the remark to the `create_test_users()` function above.
+ delay=0
+ removed=
+ subsession_dir="$homedir/subsession/$subsession/apps_rw"
+ while [ $delay -lt $MAXTRIES ]
+ do
+ if [ ! -d "$subsession_dir" ]; then
+ removed=true
+ break
+ fi
+ ((delay=delay+1))
+ sleep "$DELAYVAL"
+ done
+
+ if [ "$removed" != "true" ]; then
+ echo "Removing user $subsession failed. Bailing out!"
+ exit 1
+ fi
+ done
+}
+
+# Parse user options.
+while [ $# -gt 0 ]
+do
+ case $1 in
+ -h) printf "Usage: %s [-d delay_value] [-m max_delay] [-v verbose]\n" "$0"
+ exit 1
+ ;;
+ -d) DELAYVAL=$2
+ shift
+ ;;
+ -m) MAXTRIES=$2
+ shift
+ ;;
+ -v) VERBOSE=true
+ shift
+ ;;
+ -*) printf "Wrong option: %s. Type \`%s -h\` for help.\n" 1>&2 "$1" "$0"
+ break
+ ;;
+ esac
+ shift
+done
+
+userid=$(getent passwd "$TESTUSER" | cut -d: -f3)
+homedir=$(getent passwd "$TESTUSER" | cut -d: -f6)
+
+verbose_echo "User id: $userid, home directory: $homedir"
+
+create_test_users
+
+# Compare directories.
+skeldir="/etc/skel/apps_rw"
+templatefiles=$(find "$skeldir" -not -wholename "$skeldir" | wc -l)
+
+for subsession in "${TEST_SUBSESSIONS[@]}"; do
+ echo "Checking subsession: $subsession"
+ subsession_dir="$homedir/subsession/$subsession/apps_rw"
+ totalfiles=0
+
+ while IFS= read -r -d '' f
+ do
+ verbose_echo "Checking $f..."
+ templf="${f/"$subsession_dir"/$skeldir}"
+
+ # Check if permissions are correct
+ usergroup=$(stat --format '%U:%G' "$f")
+ user=$(echo "$usergroup" | cut -d: -f1)
+ group=$(echo "$usergroup" | cut -d: -f2)
+ if [ "$user" != "$TESTUSER" ] || [ "$group" != "$GROUP" ]; then
+ echo "$f: incorrect permissions set!"
+ exit 1
+ fi
+
+ # Check SMACK attributes (access, transmute, etc.)
+ smackattrs=$(chsmack "$f")
+ fattrs="${smackattrs/"$f"/}"
+ templateattrs=$(chsmack "$templf")
+ tattrs="${templateattrs/"$templf"/}"
+
+ if [ "$fattrs" != "$tattrs" ]; then
+ echo "$f: SMACK attributes differ from the template!"
+ exit 1
+ fi
+
+ # Compare the contents of the files by comparing SHA256 sums.
+ # N.B. In the Linux world, most file-system functions follow the symlinks
+ # by default. However we don't want that, that's why we need two separate
+ # code paths here.
+ if [ -L "$f" ]; then
+ verbose_echo "$f is a link"
+ origl=$(readlink "$f" | sha256sum | cut -d' ' -f1)
+ copiedl=$(readlink "$templf" | sha256sum | cut -d' ' -f1)
+ if [ "$origl" != "$copiedl" ]; then
+ echo "$f: link points to a different file than the one from the template!"
+ exit 1
+ fi
+ elif [ -f "$f" ]; then
+ verbose_echo "$f is a file"
+ origf=$(sha256sum "$f" | cut -d' ' -f1)
+ copiedf=$(sha256sum "$templf" | cut -d' ' -f1)
+ if [ "$origf" != "$copiedf" ]; then
+ echo "$f: file content differs from the template!"
+ exit 1
+ fi
+ fi
+
+ ((totalfiles=totalfiles+1))
+ done < <(find "$subsession_dir" \( -type d -o -type f -o -type l \) -not -wholename "$subsession_dir" -print0)
+ verbose_echo "Total number of files: $totalfiles"
+
+ # Since the above comparison is based on the contents of the target directory,
+ # it's possible that it will come out as false positive when all existing
+ # files match the source files, but not all source files have been copied.
+ # The remedy for this is to add a simple comparsion of the number of files
+ # in the two directories.
+ if [ "$templatefiles" != "$totalfiles" ]; then
+ echo "Number of files in subsession $subsession vary from the number of files in the template!"
+ exit 1
+ fi
+done
+
+remove_test_users
+
+exit 0
+