Mavericks - CocoaDialog at logout

dwandro92
Contributor III

Our organization has been using CocoaDialog progress bars at logout to display the installation progress of non-Apple and Apple software updates. Recently I've been working on our Mavericks image (which has been quite a pain, to say the least) and we have noticed that CocoaDialog progress bars aren't being displayed during logout. I am positive that the policy scope is correct and that the update actions are running, but the dialogs are just not being displayed. In addition, I have verified that the progress bar windows are being displayed correctly when executed while I am logged in. Has anyone seen this problem and found a solution, or is there any other application we could use to accomplish this task on 10.9? Please let me know.

Thank you,

Dakota Wandro
Imaging Specialist

71 REPLIES 71

kalikkalik
New Contributor

Dakota,

We've seen a few odd things like this lately, but we're largely moving away from CocoaDialog; it hasn't been updated in two years...we're not expecting it to work in "beta" mode forever...some folks are using AppleScript/Obj-C, and some have gone straight to cocoa. Depending on what you need to do, it's not that hard. I knocked out 3 custom dialog screens with progress meters in about a day (with testing).

Thanks,
j

mm2270
Legendary Contributor III

I use cocoaDialog quite a bit. Although true that the last beta hasn't been updated in close to 2 years now, it miraculously still mostly works in Mavericks. The problem you're facing likely has more to do with Mavericks and additional sandboxing that Apple includes in each major new version of OS X than it does with cocoaDialog strictly. Apple makes it harder in each version to display dialogs over the login window or at various stages of a logout. Some tools I've used don't even work while a user is logged in unless I script it to run the dialogs as the current logged in user. This may be the case here.

Can you post an example of the code you're using to display the progress bars? I may be able to make some suggestions that will get it working again (no guarantees!)

dwandro92
Contributor III

Here is the script that is run during logout on our clients. It is used in a policy with 3 parameters:

Parameter #1: Policy ID of the actual policy which is triggered by the script to install/upgrade the software
Parameter #2: Name of application being installed/upgraded
Parameter #3: Estimated install time in minutes (e.g. 5-10)

#!/bin/sh

# Set path to CocoaDialog binary
cdPath="/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog"

# Set ID of policy which is triggered by the script to install/upgrade the software
pid="$4"

# Set name of software which is being installed/upgraded
policyName="$5"

# Set estimated install time of policy in minutes (e.g. 5-10)
policytime="$6"

# Set default percentage for progress bar. This can be anything, since an indeterminate progress bar is being used
thePct="10"

# Get OS version string
OS=`/usr/bin/defaults read /System/Library/CoreServices/SystemVersion ProductVersion | awk '{print substr($1,1,4)}'`

# Output variable values to log
echo "Operating System is $OS";
echo "policy_id is $pid";
echo "Policy name is $policyName"
echo "install_minutes is $policytime";

# Create the name pipe input for the progressbar
rm -f /tmp/hpipe
mkfifo /tmp/hpipe
sleep 0.2

# Display indeterminate progress bar
echo "Displaying progress bar window."
"$cdPath" progressbar --indeterminate --title "Software Update" --text "Preparing update.." 
--posX "right" --posY "top" --width 350 --height 125 --float --icon info < /tmp/hpipe &

# Send progress through the named pipe
exec 3<> /tmp/hpipe

# While actions are being performed
/usr/sbin/jamf policy -id "$pid" 2>&1 | while read line; do
    # Output status message to progress bar
    echo "$thePct Installing $policyName... Approximate install time is $policytime minutes. Please do not shutdown." >&3
done

# Wait 1 second before shutting off progressbar
sleep 1

# Turn off progress bar by closing file descriptor 3 and removing the named pipe
echo "Closing progress bar."
exec 3>&-
rm -f /tmp/hpipe

# Exit script
exit 0

I cut out a lot of the unnecessary text from the script we're using and added more verbose comments to make it easier to read. Let me know what your thoughts are.

bentoms
Release Candidate Programs Tester

We show the indeterminate progress bar @ logout as part of our Software Update process on 10.7+ Using the cocoa dialog beta.

I'll compare code tomorrow & will advise.

mm2270
Legendary Contributor III

@dwandro92][/url][/url][/url][/url][/url

You do your progress bars pretty similar to mine in that you create a named pipe and assign a file descriptor to it.

So one thing I found recently when I was testing something on Mavericks that uses cocoaDialog progress bars is that somehow the file descriptor ended up being in use and if that happens, you won't get any progress bar. Note that you can actually use any file descriptor you want from 3 - 255, so you're not limited to using the next available one after 1 & 2. I've started getting into the habit of assigning much higher file descriptors, like 10, 20, etc. There's no harm in doing this from what i understand about it.
The other thing I'm also including now is a close for the file descriptor right before opening it and assigning to my named pipe. I did this because if for any reason your script quits/exits before it reaches the point where you close the file descriptor, it may leave it in an open/used state and the next progress bar that tries to use it will fail to appear.

So in your code above, try doing something like this:

# Create the name pipe input for the progressbar
rm -f /tmp/hpipe
mkfifo /tmp/hpipe

**# Close the file descriptor prior to opening and assigning it
exec 10>&-**

sleep 0.2

<--- snip --->

**exec 10<> /tmp/hpipe**

<--- snip --->

# Turn off progress bar by closing file descriptor 3 and removing the named pipe
echo "Closing progress bar."
**exec 10>&-**
rm -f /tmp/hpipe

# Exit script
exit 0

I snipped out the longer sections and bolded the areas where I made changes from your script. Again, I'm not sure why, but progress bars that worked perfectly under Mountain Lion and lower OSes started not appearing in my scripts when run on Mavericks and as soon as I assigned a higher file descriptor they began working again. I'm not sure if 10.9 is somehow using additional descriptors or if some bug in my code was causing it, but that fixed my issues.

I don't know for sure if that's the issue, but hopefully it will help. Post back with results when you can.

bentoms
Release Candidate Programs Tester

here are what i think are the relevant lines from my script:

#!/bin/sh

    # Remove temp pipe file if exists
    rm -f /tmp/cdupdatepipe

    # Create temp pipe file
    mkfifo /tmp/cdupdatepipe

    sleep 0.2

        /usr/local/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog progressbar --indeterminate --title "Updates Are Being Installed, A Restart Will Follow" --height "128" --width "500" --icon "installer" --icon-height "96" --icon-width "96" --float < /tmp/cdupdatepipe &

        # Echo out to pipe to be relayed to cocoaDialog window
        exec 3<> /tmp/cdupdatepipe

bentoms
Release Candidate Programs Tester

Hi Guys.. sorry it's been a while.. but looks like CocoaDialog actually isn't showing @ logout for me either.

BUT I'm also looking at it on a Mac running 10.9.2 beta..

I'm going to have a play & will report back, FWIW the progress bar etc works fine in a user session.. just not showing @ logout

quedayone
Contributor

Posted 1/21/14 at 10:52 AM by kalikkalik

I knocked out 3 custom dialog screens with progress meters in about a day (with testing).

kalikkalik, mind giving us some more info, or sharing examples?
Thanks in advance!

qUe

kalikkalik
New Contributor

qUe,

Hmmm..I'll have to think about what I can offer, since those (windows) are not my IP. I wouldn't mind throwing some code behind a new community-driven version of CocoaDialog, albeit a bit leaner. As it is my fingers are in a few too many dev pots these days!

Let me know what the community is looking for, and I'll start thinking about a way to wrap some code around it. Who knows, maybe CD just needs to be "refreshed".

-j

quedayone
Contributor

All I need to do is ask users at log out if they want to check for and install updates.
If they click yes, a policy runs and shows a "progress bar" as the policy runs. This policy installs apple updates from our internal apple update server, installs any cached packages, and checks my internal adobe update server for adobe updates, then runs recon and restarts.
If they click no computer simply restarts.

I am currently doing this with CocoaDialog on 10.8 and it works great.

This is the script I am using:

#!/bin/bash
# COLLE+McVOY Script to trigger software updates
# Will Pierce, created 130501
# Last modified 130807
# Added a 1 min timer to do nothing if user walks away
# Added the software update icon
# Fixed the text flow, no there is no space on the 2nd line

# Set the date as a variable 
the_date=`date "+%Y-%m-%d %H:%M:%S"`
# This is the path to CocoaDialog
CD="/Applications/Utilities/CocoaDialog.app/Contents/MacOS/CocoaDialog"

# Create a yes no message box with thesoftware update icon that will time out and restart with out updateing after 1 min
# Or if user hits the yes button install updates and restart
rv=`$CD yesno-msgbox --icon-file /System/Library/CoreServices/Software Update.app/Contents/Resources/SoftwareUpdate.icns --timeout 60 --no-cancel --string-output --no-newline 
    --text "Would you like to check for and install updates?" 
    --informative-text "Click YES to update now & restart.
Click NO to restart as normal. No response after 1 min will restart as normal."`
echo "$rv"
if [ "$rv" == "Yes" ]; then
# User responds yes
# Add the date updates were run to com.cm.imaging plist so we can report on this
/usr/bin/defaults write /Library/Preferences/com.cm.imaging UpdatesRunDate "$the_date" 

elif [ "$rv" == "No" ]; then
# User responds no
# Add the date updates were canceled to com.cm.imaging plist so we can report on this
/usr/bin/defaults write /Library/Preferences/com.cm.imaging UpdatesCancelDate "$the_date" 
exit 0

elif [ "$rv" == "timeout" ]; then
# No User responce after 1 min
# Add the date updates were canceled to com.cm.imaging plist so we can report on this
/usr/bin/defaults write /Library/Preferences/com.cm.imaging UpdatesCancelDate "$the_date" 
exit 0
fi
# Get the policy ID and Name to run from the JSS script variables 4 & 5
# Look at the policy triggering the script for the info
pid="$4"
policyName="5$"
thePct="10"

## Create the name pipe input for the progressbar
rm -f /tmp/hpipe
mkfifo /tmp/hpipe
sleep 0.2

## Display indeterminate progress bar
echo "Displaying progress bar window."
"$CD" progressbar --indeterminate --title "COLLE+McVOY Updates Running" --text "Preparing policy..." 
--posX "right" --posY "top" --width 525 --float < /tmp/hpipe &

## Send progress through the named pipe
exec 3<> /tmp/hpipe

/usr/sbin/jamf policy -id "$pid" 2>&1 | while read line; do
## Get output from current installation and send to progressbar
# outPut=$( echo "$line" | egrep -i "install|executing|policy|AAMEE|downloading" | sed 's/^[ ]*//g' )
outPut=$( echo "$line" | sed 's/^[ ]*//g' )
if [ "$outPut" != "" ]; then
echo "$thePct $outPut" >&3
else
echo "$thePct Running $policyName..." >&3
fi
done

## Wait 1 second before shutting off progressbar
sleep 1

# Turn off progress bar by closing file descriptor 3 and removing the named pipe
echo "Closing progress bar."
exec 3>&-
rm -f /tmp/hpipe

exit 0

.

loceee
Contributor

Hmm... I'd be thinking it's a sandboxing issue too. It affects my patchoo system.

http://patchoo.github.io

Need to find a solution if anyone has come up with anything?

bentoms
Release Candidate Programs Tester

@loceee.. That sucks! I was going to ask.

I think next step will be to try with a Signed copy of Cocoa Dialog.

loceee
Contributor

Over to you... I am trying to compile this newer fork and sign, but don't have any idea what I am doing, doesn't seem to compile on 10.7 sdk. ...https://github.com/cooljeanius/cocoadialog

bentoms
Release Candidate Programs Tester

@loceee.. Geez... Pressure!

I'll have a nose around today, FWIW.. We make 3 x CD calls @ logout. The last seems to work. So might be a time thing too.

loceee
Contributor

Are you saying that you it does successfully launch? It might be an issue calling it from a jamf policy script...? I will do some more experimentation.. perhaps with a direct helper logout hook script. Next week. :)

sean
Valued Contributor

If you are bothered by the lack of updates for cocoaDialog, then why not check out Pashua.

http://www.bluem.net/en/mac/pashua/

Actively being updated, has more options and better flexibility for multiple elements in a single window.

I had a similar experience as you regarding 10.9 and our logout script that launches iHook using a LogoutHook. This script is now launched by a /Library/LaunchAgent and will overlay at the login window.

{
    Label = "[your label here]";
    LimitLoadToSessionType =     (
        LoginWindow
    );
    Program = "[path to your script]";
    RunAtLoad = 1;
}

mm2270
Legendary Contributor III

Yeah I've looked at Pashua, but I actually found it to be much more complex to use than cocoaDialog. It requires setting up a configuration file that then gets fed back to the application to present dialogs. Contrast this to cocoaDialog which can accept simple flags in the call to the executable to set up the text and other parameters. In addition, the other nice thing about cocoaDialog is that you don't actually have to set most of the parameters, like the window width and height, icon size, etc as it will adjust those as needed, yet, its still an option if you want more granular control (at least with the 3.x beta).
It seems Pashua requires setting almost everything up including positioning of elements and their sizes, or you end up with very strange results. Pashua also doesn't do dialogs without close buttons like cocoaDialog does. You also need to explicitly set up the NSUIElement = 1 flag for the application or it shows up in the Dock when it runs. Finally, to my knowledge, it doesn't do progress bars. That last item is actually very relevant since the recent posts on this thread are in relation to showing a progress bar over the LoginWindow.

As for iHook, yes, that's an option, but its butt ugly in my opinion. It also hasn't been updated in some time and as you found, doesn't really work reliably anymore as a result.

Its just my personal opinion, but despite its being long in the tooth, cocoaDialog is still the easiest to use dialoging tool with the most amount of options (bubbles, standard dialogs, progress bar, sliders, checkboxes, etc) I just wish it would get some needed attention.

kalikkalik
New Contributor

You need to have people with free time, or people who are willing to donate/kickstart the project.
Both are a little hard to come by these days...

franton
Valued Contributor III

In defence of iHook, it still works wonderfully for us on loginwindow for both 10.8 and 10.9. . Never tried using it at logout on 10.8+ .

franton
Valued Contributor III

I just made a feature request for JAMF to take up CocoaDialog.
https://jamfnation.jamfsoftware.com/featureRequest.html?id=2282

mm2270
Legendary Contributor III

That'll get my vote. Not sure if JAMF will actually do it, but if you don't ask…
I would be sad if all that functionality was lost because of lack of development.

NightFlight
New Contributor III

Anyone seen any method to getting any sort of output into the logouthook display? I'm using NFS mounts and rsync to bring data in on the loginhook and back out on the logouthook. However I can't notify the user of progress on logout, or any sort of notice - even a simple 'please wait' would do.

bentoms
Release Candidate Programs Tester

paging @GaToRAiD

GaToRAiD
Contributor II

@bentoms][/url really? now i get a paging system?

Ok, so here is a little bit of what you will need to do, I will post the full script i use on Monday when i return to work.

But the reason you are noticing it do this behavior, is because you cant initiate a logout and be able to call CocoaDialog, so you have to fake the logout. Here is a few functions that I use to do this for me.

getAppList()
(
    applist=$(sudo -u $user osascript -e "tell application "System Events" to return displayed name of every application process whose (background only is false and displayed name is not "Finder")")
    echo $applist
)
quitAllApps()
(
    applist=$(getAppList)
    applistarray=$(echo $applist | sed -e 's/^/"/' -e 's/$/"/' -e 's/, /" "/g')
    eval set $applistarray
    for appname in "$@"
    do
        secho "trying to quit: $appname ..."
        sudo -u $user osascript -e "ignoring application responses" -e "tell application "$appname" to quit" -e "end ignoring"
    done
)
fauxLogout()
{
    user=$(who | grep console | awk '{print $1}')
    waitforlogout=30
    tryquitevery=3
    while [ "$(getAppList)" != "" ]
    do
        for (( c=1; c<=(( $waitforlogout / $tryquitevery )); c++ ))
        do
            quitAllApps
            #check if all apps are quit break if so, otherwise fire every $tryquitevery
            [ "$(getAppList)" == "" ] && break
            sleep $tryquitevery
        done
        if [ "$(getAppList)" != "" ]
        then
            # if we still haven't quit all Apps
            dialogtimeout=60
            secho "apps are still running after $waitforlogout seconds, prompting user and trying quit loop again.."
            displayDialog "Ensure you have saved your documents and quit any open applications. You can Force Quit applications that aren't responding by pressing CMD-SHIFT-ESC." "Logging out" "The Logout process has stalled" "caution" "Continue Logout"
            quitAllApps
        fi
    done


    # lock screen
    /System/Library/CoreServices/RemoteManagement/AppleVNCServer.bundle/Contents/Support/LockScreen.app/Contents/MacOS/LockScreen & 2> /dev/null
    sleep 1
    # makes changes to cocoaDialog
    defaults write "${cdialog}/Contents/Info.plist" LSUIElement -int 0
    defaults write "${cdialog}/Contents/Info.plist" LSUIPresentationMode -int 3
    chmod 644 "${cdialog}/Contents/Info.plist"
}

Obviously there are some variables missing in here, but you should be able to figure them out. But these are just the functions I use to do the process. You can also look at patchoo's code, some of this information comes directly from it. This is basically the same process they are using to do it.

Hope this helps.

bentoms
Release Candidate Programs Tester

@GaToRAiD, cheers fella! Looking forward to Monday :)

GaToRAiD
Contributor II

I ment to add, if you are trying to trigger this to run at logout, I would try to capture the logout by using a launchd with the loginwindow argument in the plist. This should be able to capture it and you can stop it and run your script which will fake the logout, then actually log them out after running.

I will hopefully be able to test this, as right now I'm not doing this as a logout process, I'm doing it as a timed function.

loceee
Contributor

@GaToRAiD Can you elaborate how you would capture a logout via the method you've mentioned?

I would be great to re-instate the "you are shutting down, install updates now" prompt in Patchoo for 10.8+ when people are initiating a logout or shutdown themselves.

But I think we all need to start concentrating on putting cocoaDialog to bed. Sad, but no one seems to have taken the reigns on it. :(

JAMF please add a progress bar handler to jamfHelper and I can migrate to use it exclusively!

loceee
Contributor

I've been thinking about how we might be able to kludge a progressbar out of jamfHelper... it's almost acceptable, but there's a white flash when you fire jamfHelper in fs mode. Otherwise you could technically toggle two jamfHelper processes and kludge a progress bar. Toggling two utility or hud windows is pretty klunky though. Back to the drawing board...

external image link
external image link

GaToRAiD
Contributor II

The main issue with the com.apple.loginwindow's logout hook is that from my research by design, apple doesn't want things to be able to run in a gui fashion once the logout process has begun. This is of course from Mavericks+, so the tricky part is being able to tell when a logout has happened. I've been experimenting with a way to see that the trigger of logout, shutdown, etc has happened. Now, I've only been able to monitor this behavior with a tool that is built in object C. I'm still trying to do some digging to see if there is a process that I can watch for that is the trigger to this event.

nigelg
Contributor

The jamfHelper app can display during logout. How do JAMF do it? I am going to try asking JAMF support and see if they are willing to share.

bentoms
Release Candidate Programs Tester

@nigelg If you download CocoaDialog's source, there are many errors about depreciated code when compiling the app.

I'm guessing that's not going to help.

nigelg
Contributor

@bentoms I want to display my own cocoa app at logout as we do our own in-house syncing. jamfHelper shows at logout so I want to know how jamf have permissions to be able to do it. I have tried creating a basic cocoa app and can display it at login but not during logout. I have tried adding it directly to the jamf logouthook.sh which launches jamfHelper but that didn't work (obviously) so theres something about jamfHelper that means it has permission to display over the logout window. I remember reading something about sockets some months ago when there was a jamfHelper bug and it wouldn't display for a couple of versions.

daz_wallace
Contributor III

We hit an issue which sounds similar starting with Mavericks (Mac OS X 10.9.x). We used to run iHook with some pretty pictures etc at logout whilst a sync ran.

We ended up utilising Big Honking Text instead and it meet our needs in a good enough way.

Darren

russeller
Contributor III

Hello- I stumbled across this recently: http://jacobsalmela.com/os-x-yosemite-osascript-enabling-access-assistive-devices/

The author was trying to get the command line tool osascript to run at the loginwindow so he could use the ARD UNIX command to enter the username/password info en masse. He created a python script to help automate the entry of command line or apps to the Accessibility pane in Yosemite. Not sure if this would help in this situation, I'm guessing the CocoaDialog issue is something else.

mm2270
Legendary Contributor III

Those are two different issues. Accessibility settings in the last several OS X versions prevents applications from controlling the UI with automation tasks, like clicking buttons and such, until they are added into the Accessibility pane and given that access. That's not the same issue as displaying a dialog of some kind over the actual login window. I'm not sure what an application needs to be able to do that, but it may need to be a signed application to start; not sure.

russeller
Contributor III

@mm2270 that makes sense. I figured it was something like that. Thanks for clarifying.

loceee
Contributor

Mr Neagle has responded with the links to the important code that makes it happen with Munki's tools in this thread.

loceee
Contributor

...hold the phone.

With a fork that I managed to get to compile on 10.10 ... https://github.com/cooljeanius/cocoadialog

And some changes those hints offered up by greg, I've got cocoaDialog presenting a dialog over the loginwindow run by a launchagent at the loginwindow.

Massive disclaimer that I don't really know what I am doing at all in cocoa. Stay tuned.

4e85a6b4096649c98a7ba1df1dff56d6

loceee
Contributor