1

background

I've been working on a backup script that runs occasionally via launchd. When it runs, it prompts me with something like:

osascript -e "display dialog \"Is now a good time to back up?\""

This works great when the system is open/online, but it seems to hang if the lid is closed or screen is locked/off. A tolerable way to test this is to SSH into the system as the same user with the desktop active, run a command like the one above, and observe that the dialog pops up.

If I run the same command with the system locked, it just hangs. If I unlock/open the system, the command doesn't finish, and the dialog doesn't appear.

It looks like I can simulate the same condition with like this:

pmset displaysleepnow; osascript -e "display dialog \"never never land\""

question

Is anyone aware of a way to detect this condition (at launchd, bash, or applescript level) so that I can do any of:

  1. keep the job from running at all until the system is active
  2. sleep the script until I can display a dialog without it hanging
  3. abort the script run before it hangs

I'm not keen on it, but the best I've been able to figure out so far involves putting a long timeout on the first dialog in the script and bailing out if it never gets answered, i.e.:

osascript -e "display dialog \"Is now a good time to back up?\" giving up after 600"
2

This should keep waiting until the screen is on:

set screenOff to true
repeat until screenOff is false
    set screenOff to (do shell script "ioreg -c AppleBacklightDisplay | grep dsyp") contains "\"dsyp\"={\"min\"=0,\"max\"=2,\"value\"=0}"
end repeat

display dialog "Is now a good time to back up?"
  • Tentatively accepting this since initial test suggests this works pretty straightforwardly. Thanks! I don't have the energy at the moment, but I'll try to convert this solution into something fairly equivalent with an approach I found this evening involving the pmset command, so that I can road-test both for a little bit and see if there are any edge-case conditions. – abathur Apr 3 at 6:03
  • @abathur @abc: Just outa' curiosity, could caffeinate have a role in keeping the system fully awake while the backup script is running? – Seamus Apr 3 at 12:52
  • @Seamus I would assume so (but I don't think it would address the hang at issue in the thread). – abathur Apr 3 at 14:09
1

EDIT—Authors' note: this answer did not solve the problem. Answer if you can!


System Events knows when the screen is locked. I believe all AppleScript delays and timeouts pause when the Mac is actually asleep. I switched to a heredoc as it is getting lengthy. Should really save it as a bona fide script file.

Try adapting something like:

osascript <<'SCRIPT'
delay 5
set userInteractionBlocked to true
repeat until userInteractionBlocked is false
  tell application "System Events" to set userInteractionBlocked to (running of screen saver preferences)
  if userInteractionBlocked then delay 300
end repeat
display dialog "Now a good time for a backup?" with icon 2 buttons {"Later", "Backup"} default button 2
SCRIPT

I used the delay 5 in to provide time to start the screen saver for testing—not important to its function.

  • Good idea. It doesn't look like this works for lock/sleep/lid-closed conditions, but this probably works well for desktop systems configured to use a screensaver. I optimistically checked the equivalent security preferences object, but no dice. – abathur Apr 2 at 21:46
  • Huh. I cannot reproduce your hang behaviour then. Bummer. I'll edit the answer to suit. "Comments are not for conversation", but does it stay awake when closing the lid? Will keep poking—yours is a great and obvious question. Suspecting though that the 'right answer' will not be written in Apple Script. – Joel Reid Apr 3 at 0:04
  • It can if it's plugged in, at least. Also, edited question both to clarify that applescript isn't a requirement for the fix, per se (it's just hanging during the execution of the applescript) and to give the simplest way I've found to re-produce the condition. – abathur Apr 3 at 5:53
1

EDIT: I stumbled into what looked like a more direct answer, presented below, but @abc's method has proven more accurate over the course of the day. I suspect there may still be a good way to use queries in pmset to accomplish this fairly directly (perhaps by combining more than one indicator), but I'll probably only pursue that further if I notice any edge cases with @abc's ioreg approach.


I noticed something in the first half of the output from pmset -g assertions:

Assertion status system-wide:
   BackgroundTask                 0
   ApplePushServiceTask           0
   UserIsActive                   1
   PreventUserIdleDisplaySleep    0
   PreventSystemSleep             0
   ExternalMedia                  0
   PreventUserIdleSystemSleep     1
   NetworkClientActive            0

The next to last option, PreventUserIdleSystemSleep, appears to be 0/false when the lock screen is up or the lid is closed but the system hasn't gone to sleep yet (EDIT: this understanding is incomplete; I've since observed 0 values here even while the system is full-on and in use). It looks like this supports something similar to @abc's answer, either by skipping the backup routine when idle:

active="$(pmset -g assertions | grep -oP "PreventUserIdleSystemSleep\s+\K\d")"
if [ $active -ne 0 ]; then
    # backup
fi

Or holding off until the system isn't idle:

active="$(pmset -g assertions | grep -oP "PreventUserIdleSystemSleep\s+\K\d")"
until [ $active -ne 0 ]; do
    active="$(pmset -g assertions | grep -oP "PreventUserIdleSystemSleep\s+\K\d")"
    sleep 10
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .