[Pm-utils] Abort suspend/resume sanely on hook failure

Victor Lowther victor.lowther at gmail.com
Sun Jun 22 09:56:09 PDT 2008


This patch (against the master fd.o repository) adds support for
aborting the suspend/resume process if a hook exits with a return value
of something besides 0 or $NA.  It also adds support to pm-action to
exit with a non zero exit code if suspend/resume was aborted for any
reason.

To support these changes, run_hooks has been modified to track the last
hook that ran sucessfully, and to skip all hooks that it did not run due
to inhibition when asked to run hooks in reverse.

I have been running this code on my development system for a couple of
weeks, and it seems stable enough for me.  

Comments?

diff --git a/pm/HOWTO.hooks b/pm/HOWTO.hooks
index 4f412eb..816ebba 100644
--- a/pm/HOWTO.hooks
+++ b/pm/HOWTO.hooks
@@ -30,6 +30,19 @@ NAMING SCHEME
 
 All hooks are run in lexical sort order according to the C locale.
 
+HOOK EXIT CODES
+
+In normal operation, hooks should only return either 0 or 254 as exit codes.
+0 indicates that the hook performed its task normally.
+254 indicates that the hook is not applicable to this system.
+
+Any other return code is interpreted by the pm-utils machinery as a signal 
+from the hook that it should abort whatever it is doing. When running sleep.d
+hooks, that means that pm-utils stops running hooks, aborts the suspend/resume
+process, calls any hooks that ran sucessfully prior to this one with the 
+appropriate wakeup options, and exits with a non-zero exit code. When running
+power.d hooks, any hooks after this one will be skipped.
+
 SLEEP.D SPECIFIC NOTES
 
 For any given sleep/wakeup cycle, the hooks in sleep.d are run twice:
@@ -93,3 +106,8 @@ the hook. This will make the following convenience functions available:
 11: disablehook
 	Prevent a hook from running.  The exact name of the hook (including
 	numberic prefix) must be passed.
+12: inhibit
+	Inhibit the suspend/hibernate process.  pm-utils will not try to
+	hibernate the system after this function is called.
+13: inhibited
+	Test to see if inhibit has been called.
diff --git a/pm/functions.in b/pm/functions.in
index edee445..5452fb4 100644
--- a/pm/functions.in
+++ b/pm/functions.in
@@ -189,6 +189,19 @@ restorestate()
 	state_exists "$1" && cat "${STORAGEDIR}/state:$1"
 }
 
+# Inhibit suspend/resume and running any more hooks.
+# Any parameters passed ti this function will be saved in the inhibit file.
+inhibit()
+{
+    echo "$*" > "$INHIBIT"
+}
+
+# Are we inhibited?
+inhibited()
+{
+    [ -f "$INHIBIT" ]
+}
+
 # If we were told by the user to ignore some parameters from HAL.
 # remove parameters from our list
 remove_parameters() {
diff --git a/pm/pm-functions.in b/pm/pm-functions.in
index 492cb8b..9c1c297 100644
--- a/pm/pm-functions.in
+++ b/pm/pm-functions.in
@@ -19,7 +19,6 @@ PM_UTILS_ETCDIR="@PM-UTILS-SYSCONFDIR@"
 PM_UTILS_RUNDIR="/var/run/pm-utils"
 
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:"${PM_UTILS_LIBDIR}"/bin
-INHIBIT="${PM_UTILS_RUNDIR}/inhibit"
 PM_LOGFILE="${PM_LOGFILE:=/var/log/pm-suspend.log}"
 TEMPORARY_CPUFREQ_GOVERNOR="performance"
 LOCKDIR="${PM_UTILS_RUNDIR}/locks"
@@ -43,6 +42,7 @@ HOOK_BLACKLIST=""
 ADD_PARAMETERS=""
 DROP_PARAMETERS=""
 PARAMETERS="${STORAGEDIR}/parameters"
+INHIBIT="${STORAGEDIR}/inhibit"
 PM_CMDLINE="$*"
 
 [ -f "${PM_UTILS_LIBDIR}"/defaults ] && . "${PM_UTILS_LIBDIR}"/defaults
@@ -130,7 +130,7 @@ hook_exit_status(){
 		$NA) log "not applicable." ;;
 		$NX) log "not executable." ;;
 		$DX) log "disabled." ;;
-		*)   log "Returned exit code $1." ;;
+		*)   log "Returned exit code $1."; return 1 ;;
 	esac
 }
 
@@ -168,18 +168,29 @@ run_hooks() {
 		do [ -O "$f" ] && echo ${f##*/} ; done | $sort | uniq) ;
 	do
 		IFS="${oifs}"
+		# if we are running backwards, skip hooks that we did not 
+		# run going forwards due to a hook failing.
+		[ "$3" -a "$3" = "reverse" -a "$LAST_HOOK" ] && \
+		    [ "$base" \> "$LAST_HOOK" ] && continue
+		# if we have already inhibited suspend/resume,
+		# don't run any more hooks.
+		[ ! "$3" ] && inhibited && break
+		update_parameters
 		if [ -f "$syshooks/$base" ]; then
 			hook="$syshooks/$base"
 		elif [ -f "$phooks/$base" ]; then
 			hook="$phooks/$base"
 		fi
 		log -n "${hook} $2: "
-		hook_ok "$hook" && "${hook}" $2
-		hook_exit_status $?
-		update_parameters
+		hook_ok "$hook" && "${hook}" $2 
+		# if the hook exited with an unknown exit code inhibit,
+		# otherwise record this as the last hook that ran.
+		hook_exit_status $? && LAST_HOOK="$base" || inhibit
 		IFS="${nifs}"
 	done
 	IFS="${oifs}"
+	# return value is 1 if something was inhibited, 0 otherwise.
+	inhibited && return 1 || return 0
 }
 
 # Try to reinitalize the logfile. Fail unless certian criteria are met.
diff --git a/src/pm-action.in b/src/pm-action.in
index d4ddec6..58a20b6 100755
--- a/src/pm-action.in
+++ b/src/pm-action.in
@@ -82,9 +82,8 @@ rm -f "${INHIBIT}"
 
 # run the sleep hooks
 log "$(date): Running hooks for $ACTION."
-run_hooks sleep "$ACTION"
-# Sleep only if we know how and if a hook did not inhibit us.
-if [ ! -e "$INHIBIT" ]; then
+if run_hooks sleep "$ACTION"; then
+        # Sleep only if we know how and if a hook did not inhibit us.
 	log "$(date): performing $METHOD"
 	sync
 	"do_$METHOD"
@@ -94,5 +93,8 @@ else
 fi
 log "$(date): Running hooks for $REVERSE"
 # run the sleep hooks in reverse with the wakeup action
-run_hooks sleep "$REVERSE" reverse
-log "$(date): Finished."
+if run_hooks sleep "$REVERSE" reverse; then
+        log "$(date): Finished."
+else 
+        exit 1
+fi


-- 
Victor Lowther
Ubuntu Certified Professional



More information about the Pm-utils mailing list