Merge pull request #8392 from lpy4105/backport-2.28/issue/support-cpuid-for-win32

Backport 2.28: Support cpuid for win32
diff --git a/programs/demo_common.sh b/programs/demo_common.sh
new file mode 100644
index 0000000..d8fcda5
--- /dev/null
+++ b/programs/demo_common.sh
@@ -0,0 +1,137 @@
+## Common shell functions used by demo scripts programs/*/*.sh.
+
+## How to write a demo script
+## ==========================
+##
+## Include this file near the top of each demo script:
+##   . "${0%/*}/../demo_common.sh"
+##
+## Start with a "msg" call that explains the purpose of the script.
+## Then call the "depends_on" function to ensure that all config
+## dependencies are met.
+##
+## As the last thing in the script, call the cleanup function.
+##
+## You can use the functions and variables described below.
+
+set -e -u
+
+## $root_dir is the root directory of the Mbed TLS source tree.
+root_dir="${0%/*}"
+# Find a nice path to the root directory, avoiding unnecessary "../".
+# The code supports demo scripts nested up to 4 levels deep.
+# The code works no matter where the demo script is relative to the current
+# directory, even if it is called with a relative path.
+n=4 # limit the search depth
+while ! [ -d "$root_dir/programs" ] || ! [ -d "$root_dir/library" ]; do
+  if [ $n -eq 0 ]; then
+    echo >&2 "This doesn't seem to be an Mbed TLS source tree."
+    exit 125
+  fi
+  n=$((n - 1))
+  case $root_dir in
+    .) root_dir="..";;
+    ..|?*/..) root_dir="$root_dir/..";;
+    ?*/*) root_dir="${root_dir%/*}";;
+    /*) root_dir="/";;
+    *) root_dir=".";;
+  esac
+done
+
+## $programs_dir is the directory containing the sample programs.
+# Assume an in-tree build.
+programs_dir="$root_dir/programs"
+
+## msg LINE...
+## msg <TEXT_ORIGIN
+## Display an informational message.
+msg () {
+  if [ $# -eq 0 ]; then
+    sed 's/^/# /'
+  else
+    for x in "$@"; do
+      echo "# $x"
+    done
+  fi
+}
+
+## run "Message" COMMAND ARGUMENT...
+## Display the message, then run COMMAND with the specified arguments.
+run () {
+    echo
+    echo "# $1"
+    shift
+    echo "+ $*"
+    "$@"
+}
+
+## Like '!', but stop on failure with 'set -e'
+not () {
+  if "$@"; then false; fi
+}
+
+## run_bad "Message" COMMAND ARGUMENT...
+## Like run, but the command is expected to fail.
+run_bad () {
+  echo
+  echo "$1 This must fail."
+  shift
+  echo "+ ! $*"
+  not "$@"
+}
+
+## config_has SYMBOL...
+## Succeeds if the library configuration has all SYMBOLs set.
+config_has () {
+  for x in "$@"; do
+    "$programs_dir/test/query_compile_time_config" "$x"
+  done
+}
+
+## depends_on SYMBOL...
+## Exit if the library configuration does not have all SYMBOLs set.
+depends_on () {
+  m=
+  for x in "$@"; do
+    if ! config_has "$x"; then
+      m="$m $x"
+    fi
+  done
+  if [ -n "$m" ]; then
+    cat >&2 <<EOF
+$0: this demo requires the following
+configuration options to be enabled at compile time:
+ $m
+EOF
+    # Exit with a success status so that this counts as a pass for run_demos.py.
+    exit
+  fi
+}
+
+## Add the names of files to clean up to this whitespace-separated variable.
+## The file names must not contain whitespace characters.
+files_to_clean=
+
+## Call this function at the end of each script.
+## It is called automatically if the script is killed by a signal.
+cleanup () {
+  rm -f -- $files_to_clean
+}
+
+
+
+################################################################
+## End of the public interfaces. Code beyond this point is not
+## meant to be called directly from a demo script.
+
+trap 'cleanup; trap - HUP; kill -HUP $$' HUP
+trap 'cleanup; trap - INT; kill -INT $$' INT
+trap 'cleanup; trap - TERM; kill -TERM $$' TERM
+
+if config_has MBEDTLS_ENTROPY_NV_SEED; then
+  # Create a seedfile that's sufficiently long in all library configurations.
+  # This is necessary for programs that use randomness.
+  # Assume that the name of the seedfile is the default name.
+  files_to_clean="$files_to_clean seedfile"
+  dd if=/dev/urandom of=seedfile ibs=64 obs=64 count=1
+fi
diff --git a/programs/psa/key_ladder_demo.sh b/programs/psa/key_ladder_demo.sh
index e21d1ab..bb4a24f 100755
--- a/programs/psa/key_ladder_demo.sh
+++ b/programs/psa/key_ladder_demo.sh
@@ -15,36 +15,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -e -u
+. "${0%/*}/../demo_common.sh"
 
-program_name="key_ladder_demo"
-program="${0%/*}/$program_name"
-files_to_clean=
+msg <<'EOF'
+This script demonstrates the use of the PSA cryptography interface to
+create a master key, derive a key from it and use that derived key to
+wrap some data using an AEAD algorithm.
+EOF
 
-if [ ! -e "$program" ]; then
-    # Look for programs in the current directory and the directories above it
-    for dir in "." ".." "../.."; do
-        program="$dir/programs/psa/$program_name"
-        if [ -e "$program" ]; then
-            break
-        fi
-    done
-    if [ ! -e "$program" ]; then
-        echo "Could not find $program_name executable"
+depends_on MBEDTLS_SHA256_C MBEDTLS_MD_C MBEDTLS_AES_C MBEDTLS_CCM_C MBEDTLS_PSA_CRYPTO_C MBEDTLS_FS_IO
 
-        echo "If building out-of-tree, this script must be run" \
-             "from the project build directory."
-        exit 1
-    fi
-fi
-
-run () {
-    echo
-    echo "# $1"
-    shift
-    echo "+ $*"
-    "$@"
-}
+program="${0%/*}"/key_ladder_demo
 
 if [ -e master.key ]; then
     echo "# Reusing the existing master.key file."
@@ -68,7 +49,7 @@
     cmp input.txt hello_world.txt
 
 files_to_clean="$files_to_clean hellow_orld.txt"
-! run "Derive a different key and attempt to unwrap the data. This must fail." \
+run_bad "Derive a different key and attempt to unwrap the data." \
   "$program" unwrap master=master.key input=hello_world.wrap output=hellow_orld.txt label=hellow label=orld
 
 files_to_clean="$files_to_clean hello.key"
@@ -79,5 +60,4 @@
     "$program" unwrap master=hello.key label=world \
                input=hello_world.wrap output=hello_world.txt
 
-# Cleanup
-rm -f $files_to_clean
+cleanup
diff --git a/programs/test/dlopen_demo.sh b/programs/test/dlopen_demo.sh
index a6a9022..b162d7b 100755
--- a/programs/test/dlopen_demo.sh
+++ b/programs/test/dlopen_demo.sh
@@ -18,34 +18,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -e -u
+. "${0%/*}/../demo_common.sh"
 
-program_name="dlopen"
-program_dir="${0%/*}"
-program="$program_dir/$program_name"
+msg "Test the dynamic loading of libmbed*"
 
+program="$programs_dir/test/dlopen"
+library_dir="$root_dir/library"
+
+# Skip this test if we don't have a shared library build. Detect this
+# through the absence of the demo program.
 if [ ! -e "$program" ]; then
-    # Look for programs in the current directory and the directories above it
-    for dir in "." ".." "../.."; do
-        program_dir="$dir/programs/test"
-        program="$program_dir/$program_name"
-        if [ -e "$program" ]; then
-            break
-        fi
-    done
-    if [ ! -e "$program" ]; then
-        echo "Could not find $program_name program"
-
-        echo "Make sure that Mbed TLS is built as a shared library." \
-             "If building out-of-tree, this script must be run" \
-             "from the project build directory."
-        exit 1
-    fi
+    msg "$0: this demo requires a shared library build."
+    # Exit with a success status so that this counts as a pass for run_demos.py.
+    exit
 fi
 
-top_dir="$program_dir/../.."
-library_dir="$top_dir/library"
-
 # ELF-based Unix-like (Linux, *BSD, Solaris, ...)
 if [ -n "${LD_LIBRARY_PATH-}" ]; then
     LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH"
@@ -62,6 +49,6 @@
 fi
 export DYLD_LIBRARY_PATH
 
-echo "Running dynamic loading test program: $program"
-echo "Loading libraries from: $library_dir"
+msg "Running dynamic loading test program: $program"
+msg "Loading libraries from: $library_dir"
 "$program"
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index baf0537..d3e9cda 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -868,6 +868,9 @@
 
     msg "selftest: make, default config (out-of-box)" # ~10s
     programs/test/selftest
+
+    msg "program demos: make, default config (out-of-box)" # ~10s
+    tests/scripts/run_demos.py
 }
 
 component_test_default_cmake_gcc_asan () {
@@ -878,6 +881,9 @@
     msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
     make test
 
+    msg "program demos (ASan build)" # ~10s
+    tests/scripts/run_demos.py
+
     msg "test: selftest (ASan build)" # ~ 10s
     programs/test/selftest
 
@@ -1578,6 +1584,9 @@
     msg "test: cpp_dummy_build (full config, clang)" # ~ 1s
     programs/test/cpp_dummy_build
 
+    msg "program demos (full config, clang)" # ~10s
+    tests/scripts/run_demos.py
+
     msg "test: psa_constant_names (full config, clang)" # ~ 1s
     tests/scripts/test_psa_constant_names.py
 
@@ -1698,6 +1707,9 @@
 
     msg "test: full config + MBEDTLS_TEST_DEPRECATED" # ~ 30s
     make test
+
+    msg "program demos: full config + MBEDTLS_TEST_DEPRECATED" # ~10s
+    tests/scripts/run_demos.py
 }
 
 # Check that the specified libraries exist and are empty.
@@ -3353,6 +3365,9 @@
     msg "test: main suites (MSan)" # ~ 10s
     make test
 
+    msg "program demos (MSan)" # ~20s
+    tests/scripts/run_demos.py
+
     msg "test: ssl-opt.sh (MSan)" # ~ 1 min
     tests/ssl-opt.sh
 
diff --git a/tests/scripts/check_files.py b/tests/scripts/check_files.py
index 352b55e..238a83f 100755
--- a/tests/scripts/check_files.py
+++ b/tests/scripts/check_files.py
@@ -162,24 +162,6 @@
     return ext in ('.bat', '.dsp', '.dsw', '.sln', '.vcxproj')
 
 
-class PermissionIssueTracker(FileIssueTracker):
-    """Track files with bad permissions.
-
-    Files that are not executable scripts must not be executable."""
-
-    heading = "Incorrect permissions:"
-
-    # .py files can be either full scripts or modules, so they may or may
-    # not be executable.
-    suffix_exemptions = frozenset({".py"})
-
-    def check_file_for_issue(self, filepath):
-        is_executable = os.access(filepath, os.X_OK)
-        should_be_executable = filepath.endswith((".sh", ".pl"))
-        if is_executable != should_be_executable:
-            self.files_with_issues[filepath] = None
-
-
 class ShebangIssueTracker(FileIssueTracker):
     """Track files with a bad, missing or extraneous shebang line.
 
@@ -386,7 +368,6 @@
         self.logger = None
         self.setup_logger(log_file)
         self.issues_to_check = [
-            PermissionIssueTracker(),
             ShebangIssueTracker(),
             EndOfFileNewlineIssueTracker(),
             Utf8BomIssueTracker(),
diff --git a/tests/scripts/run_demos.py b/tests/scripts/run_demos.py
new file mode 100755
index 0000000..6a63d23
--- /dev/null
+++ b/tests/scripts/run_demos.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+"""Run the Mbed TLS demo scripts.
+"""
+import argparse
+import glob
+import subprocess
+import sys
+
+def run_demo(demo, quiet=False):
+    """Run the specified demo script. Return True if it succeeds."""
+    args = {}
+    if quiet:
+        args['stdout'] = subprocess.DEVNULL
+        args['stderr'] = subprocess.DEVNULL
+    returncode = subprocess.call([demo], **args)
+    return returncode == 0
+
+def run_demos(demos, quiet=False):
+    """Run the specified demos and print summary information about failures.
+
+    Return True if all demos passed and False if a demo fails.
+    """
+    failures = []
+    for demo in demos:
+        if not quiet:
+            print('#### {} ####'.format(demo))
+        success = run_demo(demo, quiet=quiet)
+        if not success:
+            failures.append(demo)
+            if not quiet:
+                print('{}: FAIL'.format(demo))
+        if quiet:
+            print('{}: {}'.format(demo, 'PASS' if success else 'FAIL'))
+        else:
+            print('')
+    successes = len(demos) - len(failures)
+    print('{}/{} demos passed'.format(successes, len(demos)))
+    if failures and not quiet:
+        print('Failures:', *failures)
+    return not failures
+
+def run_all_demos(quiet=False):
+    """Run all the available demos.
+
+    Return True if all demos passed and False if a demo fails.
+    """
+    all_demos = glob.glob('programs/*/*_demo.sh')
+    if not all_demos:
+        # Keep the message on one line. pylint: disable=line-too-long
+        raise Exception('No demos found. run_demos needs to operate from the Mbed TLS toplevel directory.')
+    return run_demos(all_demos, quiet=quiet)
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('--quiet', '-q',
+                        action='store_true',
+                        help="suppress the output of demos")
+    options = parser.parse_args()
+    success = run_all_demos(quiet=options.quiet)
+    sys.exit(0 if success else 1)
+
+if __name__ == '__main__':
+    main()