[PATCH] acpi: s3: Add new --s3-resume-hook option

Colin King colin.king at canonical.com
Tue Jan 24 09:17:25 UTC 2017


From: Colin Ian King <colin.king at canonical.com>

This new option allows one to run a script after each S3 resume
to perform additional post-resume checks, such as Blue Tooth, Wifi,
etc.  The script must be executable and has to return 0 for success
and non-zero for failure.  Failure returns by the script will abort
subsequent S3 iterations.

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 doc/fwts.1                                |  5 ++
 fwts-test/arg-help-0001/arg-help-0001.log |  4 ++
 fwts-test/arg-help-0001/arg-help-0002.log |  4 ++
 src/acpi/s3/s3.c                          | 91 +++++++++++++++++++++++++++++--
 4 files changed, 100 insertions(+), 4 deletions(-)

diff --git a/doc/fwts.1 b/doc/fwts.1
index ebd2c6b..e05c111 100644
--- a/doc/fwts.1
+++ b/doc/fwts.1
@@ -252,6 +252,11 @@ maximum time between S3 iterations.
 specified the number of multiple S3 suspend/resume tests to run. The default
 is 2 tests.
 .TP
+.B \-\-s3\-resume\-hook=hookscript
+specifies a script or program to run after each S3 resume. The hookscript must
+return 0 to indicate success, or non-zero to indicate failure.  Failures will
+abort subsequent S3 test iterations.
+.TP
 .B \-\-s3\-quirks=--quirk[,--quirk]
 specify a comma separated list of quirk arguments to pass to pm-suspend, for example: \-\-s3\-quirks=\-\-quirk\-s3\-bios,\-\-quirk\-save\-pci
 .TP
diff --git a/fwts-test/arg-help-0001/arg-help-0001.log b/fwts-test/arg-help-0001/arg-help-0001.log
index 78dd6e3..15f8c24 100644
--- a/fwts-test/arg-help-0001/arg-help-0001.log
+++ b/fwts-test/arg-help-0001/arg-help-0001.log
@@ -162,6 +162,10 @@
 --s3-quirks                  Comma separated list
                              of quirk arguments to
                              pass to pm-suspend.
+--s3-resume-hook hook        Run a hook script
+                             after each S3 resume,
+                             0 exit indicates
+                             success.
 --s3-resume-time             Maximum expected
                              resume time in
                              seconds, e.g.
diff --git a/fwts-test/arg-help-0001/arg-help-0002.log b/fwts-test/arg-help-0001/arg-help-0002.log
index 78dd6e3..15f8c24 100644
--- a/fwts-test/arg-help-0001/arg-help-0002.log
+++ b/fwts-test/arg-help-0001/arg-help-0002.log
@@ -162,6 +162,10 @@
 --s3-quirks                  Comma separated list
                              of quirk arguments to
                              pass to pm-suspend.
+--s3-resume-hook hook        Run a hook script
+                             after each S3 resume,
+                             0 exit indicates
+                             success.
 --s3-resume-time             Maximum expected
                              resume time in
                              seconds, e.g.
diff --git a/src/acpi/s3/s3.c b/src/acpi/s3/s3.c
index 9b3e7aa..6b507ab 100644
--- a/src/acpi/s3/s3.c
+++ b/src/acpi/s3/s3.c
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <errno.h>
 
 #define PM_SUSPEND_PMUTILS		"pm-suspend"
 #define PM_SUSPEND_HYBRID_PMUTILS	"pm-suspend-hybrid"
@@ -44,6 +45,7 @@ static bool s3_min_max_delay = false;
 static float s3_suspend_time = 15.0;	/* Maximum allowed suspend time */
 static float s3_resume_time = 15.0;	/* Maximum allowed resume time */
 static bool s3_hybrid = false;
+static char *s3_hook = NULL;		/* Hook to run after each S3 */
 
 static int s3_init(fwts_framework *fw)
 {
@@ -58,6 +60,50 @@ static int s3_init(fwts_framework *fw)
 	return FWTS_OK;
 }
 
+/*
+ *  s3_hook_exec()
+ *	run a given hook script
+ */
+static int s3_hook_exec(fwts_framework *fw, char *hook)
+{
+	pid_t pid;
+	int status, ret;
+
+	pid = fork();
+	if (pid < 0) {
+		fwts_log_error(fw, "Failed to fork (to run hook script), "
+			"errno=%d (%s)\n", errno, strerror(errno));
+		return FWTS_ERROR;
+	} else if (pid == 0) {
+		/* Child */
+
+		(void)execl(hook, "", NULL);
+
+		/* We only get here if execl failed */
+		fwts_log_error(fw, "Failed to execl '%s', "
+			"errno=%d (%s)\n", hook, errno, strerror(errno));
+		return FWTS_ERROR;
+	}
+
+	/* Parent */
+
+	ret = waitpid(pid, &status, 0);
+	if (ret < 0) {
+		fwts_log_error(fw, "Failed waitpid on hook script, "
+			"errno=%d (%s)\n", errno, strerror(errno));
+
+		/* Nuke child to be double sure it's gone */
+		(void)kill(pid, SIGKILL);
+	} else if (WIFEXITED(status)) {
+		fwts_log_info(fw, "Hook script '%s' returned %d\n",
+			hook, WEXITSTATUS(status));
+		return WEXITSTATUS(status) ? FWTS_ERROR : FWTS_OK;
+	} else {
+		fwts_log_error(fw, "Hook script exited abnormally\n");
+	}
+	return FWTS_ERROR;
+}
+
 /* Detect the best available power method */
 static void detect_pm_method(fwts_pm_method_vars *fwts_settings)
 {
@@ -146,6 +192,7 @@ static int wrap_pmutils_do_suspend(fwts_pm_method_vars *fwts_settings,
 static int s3_do_suspend_resume(fwts_framework *fw,
 	int *hw_errors,
 	int *pm_errors,
+	int *hook_errors,
 	int delay,
 	int percent)
 {
@@ -262,6 +309,13 @@ static int s3_do_suspend_resume(fwts_framework *fw,
 		}
 	}
 
+	if (s3_hook && (s3_hook_exec(fw, s3_hook) != FWTS_OK)) {
+		fwts_failed(fw, LOG_LEVEL_MEDIUM, "HookScriptFailed",
+			"Error executing hook script '%s', S3 cycles "
+			"will be aborted.", s3_hook);
+		(*hook_errors)++;
+	}
+
 	if (duration < delay) {
 		(*pm_errors)++;
 		fwts_failed(fw, LOG_LEVEL_MEDIUM, "ShortSuspend",
@@ -432,6 +486,7 @@ static int s3_test_multiple(fwts_framework *fw)
 	int klog_errors = 0;
 	int hw_errors = 0;
 	int pm_errors = 0;
+	int hook_errors = 0;
 	int klog_oopses = 0;
 	int klog_warn_ons = 0;
 	int suspend_too_long = 0;
@@ -449,20 +504,27 @@ static int s3_test_multiple(fwts_framework *fw)
 	if (s3_multiple == 1)
 		fwts_log_info(fw, "Defaulted to 1 test, use --s3-multiple=N to run more S3 cycles\n");
 
-	for (i=0; i<s3_multiple; i++) {
+	for (i=0; i< s3_multiple; i++) {
 		struct timeval tv;
-		int percent = (i * 100) / s3_multiple;
+		int ret, percent = (i * 100) / s3_multiple;
 		fwts_list *klog_pre, *klog_post, *klog_diff;
 		fwts_log_info(fw, "S3 cycle %d of %d\n",i+1,s3_multiple);
 
 		if ((klog_pre = fwts_klog_read()) == NULL)
 			fwts_log_error(fw, "Cannot read kernel log.");
 
-		if (s3_do_suspend_resume(fw, &hw_errors, &pm_errors, s3_sleep_delay, percent) == FWTS_OUT_OF_MEMORY) {
+		ret = s3_do_suspend_resume(fw, &hw_errors, &pm_errors,
+					   &hook_errors, s3_sleep_delay,
+					   percent);
+		if (ret == FWTS_OUT_OF_MEMORY) {
 			fwts_log_error(fw, "S3 cycle %d failed - out of memory error.", i+1);
 			fwts_klog_free(klog_pre);
 			break;
 		}
+		if (hook_errors > 0) {
+			fwts_klog_free(klog_pre);
+			break;
+		}
 
 		if ((klog_post = fwts_klog_read()) == NULL)
 			fwts_log_error(fw, "Cannot re-read kernel log.");
@@ -497,7 +559,7 @@ static int s3_test_multiple(fwts_framework *fw)
 		}
 	}
 
-	fwts_log_info(fw, "Completed %d S3 cycle(s)\n", s3_multiple);
+	fwts_log_info(fw, "Completed S3 cycle(s)\n");
 
 	if (klog_errors > 0)
 		fwts_log_info(fw, "Found %d errors in kernel log.", klog_errors);
@@ -591,6 +653,23 @@ static int s3_options_check(fwts_framework *fw)
 		fprintf(stderr, "--s3-resume-time too small.\n");
 		return FWTS_ERROR;
 	}
+	if (s3_hook) {
+		struct stat statbuf;
+		int ret;
+
+		ret = lstat(s3_hook, &statbuf);
+		if (ret < 0) {
+			fprintf(stderr, "--s3-resume-hook file '%s' cannot "
+				"be checked, errno=%d (%s)\n",
+				s3_hook, errno, strerror(errno));
+			return FWTS_ERROR;
+		}
+		if ((statbuf.st_mode & S_IXUSR) == 0) {
+			fprintf(stderr, "--s3-resume-hook file '%s' is not "
+				"executable\n", s3_hook);
+			return FWTS_ERROR;
+		}
+	}
 	return FWTS_OK;
 }
 
@@ -640,6 +719,9 @@ static int s3_options_handler(fwts_framework *fw, int argc, char * const argv[],
 		case 10:
 			s3_hybrid = true;
 			break;
+		case 11:
+			s3_hook = optarg;
+			break;
 		}
 	}
 	return FWTS_OK;
@@ -657,6 +739,7 @@ static fwts_option s3_options[] = {
 	{ "s3-suspend-time",	"", 1, "Maximum expected suspend time in seconds, e.g. --s3-suspend-time=3.5" },
 	{ "s3-resume-time", 	"", 1, "Maximum expected resume time in seconds, e.g. --s3-resume-time=5.1" },
 	{ "s3-hybrid",		"", 0, "Run S3 with hybrid sleep, i.e. saving system states as S4 does." },
+	{ "s3-resume-hook hook","", 1, "Run a hook script after each S3 resume, 0 exit indicates success." },
 	{ NULL, NULL, 0, NULL }
 };
 
-- 
2.10.2




More information about the fwts-devel mailing list