The macosxhints Forums

The macosxhints Forums (http://hintsforums.macworld.com/index.php)
-   UNIX - Newcomers (http://hintsforums.macworld.com/forumdisplay.php?f=15)
-   -   Test to see if anyone is logged on? (http://hintsforums.macworld.com/showthread.php?t=111357)

kaptagat 05-07-2010 07:23 AM

Test to see if anyone is logged on?
 
Hi

I have a startup script (called by a launch daemon) which goes off to Apple and runs softwareupdate. If a restart is required, I want the machine to restart if no one is logged on. These are lab machines which started around 15 minutes before the first classes.

Could someone please point me in the right direction as to how to check if anyone is logged onto the machine.

thanks

SirDice 05-07-2010 07:27 AM

Use the w or who commands.

kaptagat 05-07-2010 07:58 AM

Thanks. I looked into those as well as logname. What I can't figure out is how to test to see if they exist.
I want something like :-
user=$logname
if $user doesn't exist then
restart
fi

If no one is logged in, what does who or logname or return? Zero lengths strings?

SirDice 05-07-2010 09:47 AM

Quote:

Originally Posted by kaptagat (Post 581802)
I want something like :-
user=$logname
if $user doesn't exist then
restart
fi

In this case last may be more closer to what you're trying to do.

Something like last $username and process the result.

tlarkin 05-07-2010 09:47 AM

See who owns the console, every time a user logs in they gain ownership of the console, if the console is owned by root then it is at the login window.

example:
Code:

admins-imac:~ tlarkin$ ls -l /dev/console | awk '{ print $3 }'
tlarkin

I just copied and pasted that form my terminal, and as you can see the output was tlarkin instead of root.

SirDice 05-07-2010 09:51 AM

As with all things *nix, there are several ways to get the same thing ;)

Code:

last -t console | grep "still logged in"

tlarkin 05-07-2010 09:54 AM

Quote:

Originally Posted by SirDice (Post 581824)
As with all things *nix, there are several ways to get the same thing ;)

Code:

last -t console | grep "still logged in"

Yup always many different ways, Unix is like Taiji, if you have ever taken it. Every posture is said to have at least 50 applications, paralleling it to Unix in the sense that there are usually 50 different ways to accomplish the same goal.

I just prefer the console method, and that is just my opinion.

kaptagat 05-07-2010 10:50 AM

Thanks for the replies so far but I know how to get the name of the current logged on user. What I want to know is how to test if anyone is logged on.

At the end of my script, I want this to happen :-
if no one is logged on then restart
else do something else

I have been looking into trying to see if "logname" exists i.e. "not null" with something like the script below but I don't know how to test for "nullness" or even if that way can ever work. This always returns "somebody logged on" even if no one is. Remember the script runs only on startup so it is quite feasible that it is sitting there with no one logged on. There must be a quick and simple test to see if anyone is logged on, surely!

me=$(logname)
sleep 30
if [ "$me" = "[ ]" ] # test for "nullness"
then
echo "no one logged on" >> /Library/management/checkforuser
else
echo "somebody logged on" >> /Library/management/checkforuser
fi

SirDice 05-07-2010 10:58 AM

Check on the return code $?. It's zero if it succeeds and >0 if it fails.

See the man page for logname.

tlarkin 05-07-2010 11:02 AM

OK, so you want to trigger software update form the command line?

I think I would approach it this way.

Code:

#!/bin/bash

# check to see if someone is logged in

CurrentUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`

if [[ $CurrentUser != root ]]

    then /bin/echo "$CurrentUser is logged in, exiting script..."
    exit 2
    else /usr/sbin/softwareupdate COMMAND_LINE_INSTALL -i -a

fi

#once completed reboot

/sbin/shutdown -r +1 &

exit 0


kaptagat 05-07-2010 11:28 AM

Tlarkin there will be loads of users because it is a lab. I don't really care about how many or who is currently logged on. I simply want to test if anyone is logged on. I am only using logname because I can't think of another way of how to approach this. My thinking of using it is along the lines of if a variable called logname has something in it, then somebody must be logged on. If it is "null" or empty or doesn't exist, then no one can be logged on. This is probably the the wrong way but it all I can come up with for now.

SirDice, how to I check on a return code ? Something like test -z logname?

SirDice 05-07-2010 11:29 AM

I'd use a 5 minute delay on shutdown and include a system message. Just in case somebody is logged in and the script didn't notice it. That way they get ample warning to save their work.

SirDice 05-07-2010 11:45 AM

Quote:

Originally Posted by kaptagat (Post 581843)
SirDice, how to I check on a return code ? Something like test -z logname?

Code:

me=`logname`
if [ "$?" -eq "0" ]; then
    # success
else
    # Failed
fi


tlarkin 05-07-2010 11:48 AM

Quote:

Originally Posted by kaptagat (Post 581843)
Tlarkin there will be loads of users because it is a lab. I don't really care about how many or who is currently logged on. I simply want to test if anyone is logged on. I am only using logname because I can't think of another way of how to approach this. My thinking of using it is along the lines of if a variable called logname has something in it, then somebody must be logged on. If it is "null" or empty or doesn't exist, then no one can be logged on. This is probably the the wrong way but it all I can come up with for now.

SirDice, how to I check on a return code ? Something like test -z logname?

Well that is my point, if there are tons of users, then I would test to see if root owns the console. You can safely assume if something other than root owns the console a user is logged in. You could also use the last command maybe to see who is logged in, but if your script runs as root, then it will always return the root user if you check to see who is running the script. Which is another reason why I test the ownership of the console. Of course, you don't have to do it my way, because there are many ways of doing it. I am certainly not qualified enough (not quite a Unix wizard yet, still an apprentice) to tell you all the ins and outs of why or why not certain methods should apply. Hal or Hayne could probably explain that better, or maybe Trevor.

Quote:

I'd use a 5 minute delay on shutdown and include a system message. Just in case somebody is logged in and the script didn't notice it. That way they get ample warning to save their work.
Great idea!

Code:

#!/bin/bash

# check to see if someone is logged in

CurrentUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`

if [[ $CurrentUser != root ]]

    then /bin/echo "$CurrentUser is logged in, exiting script..."
    exit 2
    else /usr/sbin/softwareupdate COMMAND_LINE_INSTALL -i -a

fi

#once completed reboot

/sbin/shutdown -r +5 &

#now notify any uesr if they log in

/usr/bin/osascript <<EOF
tell Application "System Events"
to display dialog "System will be forced to reboot in 5 minutes for a mandatory system update.  Please exit and save all work and wait for it to reboot.  All unsaved work will be lost once the computer reboots.  Sorry for this inconvenience."
EOF

exit 0

I am not the best AppleScripter in the world so you may need to tweak that last bit of code but it should work.

kaptagat 05-11-2010 09:04 AM

Thanks tlarkin

Testing for root seems to work OK, I'll incorporate it in my script. If anyone else is logged on, and a restart is required, then they will get a dialog box asking them to restart, which if they ignore, will send 50 000 volts through to their seat!

SirDice 05-11-2010 09:43 AM

Quote:

Originally Posted by kaptagat (Post 582214)
If anyone else is logged on, and a restart is required, then they will get a dialog box asking them to restart, which if they ignore, will send 50 000 volts through to their seat!

My kind of admin :D

< is the BOFH where he works ;)

tlarkin 05-11-2010 09:47 AM

a few notes

I am pretty sure now you want to set the environment before the command, so COMMAND_LINE_INSTALL should be set before the softwareupdate command.

I also think you may need to drop the word "to" on the display dialog line in the AppleScript. At the time I wasn't near a Mac to test this stuff and didn't have time to look at it until now. My post is too old for me to edit.

Please test and post back a working solution.

Also, I like the 50k volts idea. That or install ejector seats at every computer, that way you can just eject the user!

ganbustein 05-11-2010 08:58 PM

Quote:

Originally Posted by tlarkin (Post 581849)

/usr/bin/osascript <<EOF
tell Application "System Events"
display dialog " -- your message here -- "
end tell
EOF

That won't work.

When someone else logs in, the console is put into that user's bootstrap namespace, and removed from all other namespaces, including yours. You can no longer see the console, and scripts you run cannot interact with the user. (I.e., they cannot display dialogs.) You'll get an error -10810 if you try. This is a visibility problem, not a permissions problem: even a script running as root can't interact with a console it can't see.

If you ssh into the machine as the currently logged in user, your session and the login session both inherit from the user's namespace, and your osascript can find the console and display dialogs, but the dialog doesn't automatically come to the front. You should tell System Events to activate before displaying the dialog, so it won't get buried under the user's windows. (Not that it matters if you can't display the dialog anyway.)

Switching to the right user with su isn't enough. You still get error -10810 with the following:
Code:

#!/bin/bash

[[ $(/usr/bin/id -u) -eq 0 ]] || {
        echo Not running as root
        exit 2; }

consoleowner=$(/bin/ls -l /dev/console | awk '{ print $3; }')

echo $consoleowner is logged in

su $consoleowner <<SCRIPT
echo -n "Now running as "; id -un

/usr/bin/osascript <<EOF
tell application "System Events"
  activate
  display dialog "Can you read this?"
end tell
EOF

SCRIPT

The trick is to find the copy of loginwindow that logged in the current user, and tell launchctl to run a subshell in the same namespace. This leads to:

Code:

#!/bin/bash

[[ $(/usr/bin/id -u) -eq 0 ]] || {
        echo Not running as root
        exit 2; }

consoleowner=$(/bin/ls -l /dev/console | awk '{ print $3; }')
consoleid=$(/usr/bin/id -u $consoleowner)

if [[ $consoleid -ne 0 ]]; then

# Just for testing, mention the problem
echo User $consoleowner is logged in

# Find the corresponding loginwindow
loginpid=$(
        /bin/ps -Aco uid,pid,comm |
        /usr/bin/awk -v n=$consoleid '($3 == "loginwindow") && ($1 == n) { print $2 }'
        )

# Show it:
echo current loginwindow is $loginpid

# Launch a subshell in the right namespace
/bin/launchctl bsexec $loginpid /bin/bash <<SCRIPT
echo -n "Now running as "; id -un

/usr/bin/osascript <<EOF
tell application "System Events"
  activate
  display dialog "Can you read this?"
end tell
EOF

SCRIPT

fi

Modify to your heart's content.

tlarkin 05-12-2010 01:08 AM

Gan-

you are right, at the login window that will not display, but if a user is logged in osascript will work. I had not fully tested it yet, but did today while at work over ssh from one iMac to another on my desk. As long as there was a user logged in doing work, it displayed. You had to run the command as root as well.

Like I said, not the strongest apple scripter out there, I am still learning.

kaptagat 05-12-2010 10:35 AM

OK finally I have got working scripts. I have tested them with a dummy log file which has the words "restart" in its last 4 lines. Now I have to wait for Apple to release an update which requires a restart.

When the machine is started, it runs softwareupdate, the output of which goes into a log file. When the update is finished, the last 4 lines of the log file is "grepped" to see if the word "restart" exists. If so, then the second script is called. This script checks the user, if it is root (nobody logged on) then the machine is restarted. If it is not "root" then an Applescript dialog box with the restart message and two buttons (restart and not now) is called.

Here is the first script :-

#!/bin/sh

sleep 60
COMMAND_LINE_INSTALL=1 export COMMAND_LINE_INSTALL
/usr/sbin/softwareupdate -i -a >> /private/var/log/autoupdate.log 2>&1
date >> /var/log/autoupdate.log
if
tail -n 4 /private/var/log/autoupdate.log | grep -e "restart"
then /Library/management/check_user
fi


Here is the second script :-

#!/bin/sh

me=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`
if
[ $me = "root" ]
then shutdown -r now
else
osascript /Library/management/restart_dialog.app
fi

I know the above is not very elegant and should be combined into one script but the nested "ifs" together with "&&'s" was beginning to make my head hurt!

ganbustein 05-12-2010 05:42 PM

Quote:

Originally Posted by tlarkin (Post 582294)
Gan-

you are right, at the login window that will not display, but if a user is logged in osascript will work. I had not fully tested it yet, but did today while at work over ssh from one iMac to another on my desk. As long as there was a user logged in doing work, it displayed.

osascript will be able to display a dialog only if the user who is logged in and doing work is the same user you ssh'ed in as.

If you ssh joe@target.local, then your session can only see things that are in joe's Mach bootstrap namespace. If bill is logged in at the machine, the console (which includes the keyboard and the screen) is in bill's Mach namespace, and you can't see it. More precisely, what you can't see is the WindowServer.

This has absolutely nothing to do with users or privilege. Even if you su or sudo to become root, you are still in joe's namespace, and root's vaunted superuser privileges won't let osascript access a device it can't see.

tlarkin 05-12-2010 06:26 PM

Quote:

Originally Posted by ganbustein (Post 582404)
osascript will be able to display a dialog only if the user who is logged in and doing work is the same user you ssh'ed in as.

If you ssh joe@target.local, then your session can only see things that are in joe's Mach bootstrap namespace. If bill is logged in at the machine, the console (which includes the keyboard and the screen) is in bill's Mach namespace, and you can't see it. More precisely, what you can't see is the WindowServer.

This has absolutely nothing to do with users or privilege. Even if you su or sudo to become root, you are still in joe's namespace, and root's vaunted superuser privileges won't let osascript access a device it can't see.

So, when you send unix command via ARD admin and select to run as root, it doesn't work for you?

ganbustein 05-12-2010 06:51 PM

I don't have ARD, and know nothing about how it works. Since ARD has to be able to see the screen, I can only presume that when a new user logs in ARD's per-process namespace has its hierarchy changed so that it's now under that user's per-user namespace.

kaptagat is launching the script as a LaunchDaemon. Such a script would run in root's namespace, and would have no access to the WindowServer if a user is logged in. (That's why output from daemons is usually to a logfile.)

tlarkin 05-12-2010 06:56 PM

Quote:

Originally Posted by ganbustein (Post 582409)
I don't have ARD, and know nothing about how it works. Since ARD has to be able to see the screen, I can only presume that when a new user logs in ARD's per-process namespace has its hierarchy changed so that it's now under that user's per-user namespace.

kaptagat is launching the script as a LaunchDaemon. Such a script would run in root's namespace, and would have no access to the WindowServer if a user is logged in. (That's why output from daemons is usually to a logfile.)

OK, thanks good to know. I will have to test some of this stuff out tomorrow when I am back in my office, if time permits of course.

thx

-T

tlarkin 05-13-2010 02:58 PM

I just tested this by logging into my iMac from another Mac, via ssh with a different user account. When I run this:

Code:

sudo osascript -e "tell application "System Events" to display dialog "Hello World!" '
It works, even if I am not the same user. If I run it with out sudo I get the error failed to connect to window server.

I got the message popped up to me when ran as root.

ganbustein 05-14-2010 08:31 AM

That's weird. It doesn't work for me on 10.6.3.

So OK, I played with it some more. Let's suppose that the target machine has two users, Abner and Barney. Abner is an admin, Barney is not. Barney is logged in, and is using the screen. From another machine, I ssh to the target machine as Abner. All commands mentioned below are entered through that ssh session.

> osascript -e 'tell application "System Events" to display dialog "Hi"'
... error -10810 ...


> sudo osascript -e 'tell application "System Events" to display dialog "Hi"'
... error -10810 ...


> osascript -e 'tell application "Finder" to display dialog "Hi"'
... error -10810 ...


> sudo osascript -e 'tell application "Finder" to display dialog "Hi"'
I hear the target machine beep. I walk over and see Finder's icon bouncing in the dock. I click on the icon, and the dialog comes to the front. I click OK to dismiss it, and back at remote machine I see...
button returned:OK

That's not the behavior you're reporting, so I decide to explore variations on the theme. Using Fast User Switching on the target machine, I log in also as Abner, and then give control of the screen back to Barney, leaving Abner's session running in the background. Back at the terminal:

> osascript -e 'tell application "System Events" to display dialog "Hi"'
... error -10810 ...


> sudo osascript -e 'tell application "System Events" to display dialog "Hi"'
There's no immediate error, but the dialog doesn't pop up either, even if I hide all of Barney's windows. I use Fast User Switching to go back to Abner's session, and still didn't see a window. I pull up Activity Monitor and see that there is indeed an osascript process running as root. While I'm scratching my head wondering what to try next, the dialog finally pops up out of nowhere. I click OK, and back at the remote machine I see:
button returned:OK

Switching the target machine back again to Barney, I try the other variants

> osascript -e 'tell application "Finder" to display dialog "Hi"'
... error -10810 ...


> sudo osascript -e 'tell application "Finder" to display dialog "Hi"'
Beep. Finder icon bouncing. I click on bouncing icon to see dialog. Click OK:
button returned:OK

I never do see the "unable to connect to Window Server" message. Error -10810 is kLSUnknownErr, a catchall error result from Launch Services.

The only consistently useful result is with:
> sudo osascript -e 'tell application "Finder" to display dialog "Hi"'

It always works no matter who is logged in, as long as Finder is running. (If Finder isn't running, we're back to error -10810.) If Finder is not frontmost, it beeps and bounces its icon to get your attention.

Telling System Events to display the dialog doesn't always work, and even when it shows the dialog it doesn't bring it to the front.

tlarkin 05-14-2010 09:32 AM

This is what I did:

iMac 1 logged in as me, local admin

iMac 2 logged in as me, local admin

From iMac 2 I ssh'd into iMac 1 with a different account, one that is used for management purposes (also an admin account). If I ran the osascript command with out sudo I got an error, if I ran it with sudo it worked.

iMac 1 is 10.5.8 and iMac 2 is 10.6.3. Though, you are probably right on the finder always running, the problem with the finder is that it doesn't bring it to the front like you mentioned.

Also, as root if I run the say command it also worked for me.

ganbustein 05-14-2010 03:33 PM

So we're probably looking at a difference between 10.5.8 and 10.6.3.

But the advantage of Finder is that it will at least tell you that it has something to say if it's not already in the front. System Events is never in the front (unless your osa script explicitly activates it) and has no dock icon nor any other means to let you know it has a dialog it wants you to see. A dialog from System Events usually gets buried behind all the other user windows. (At least on 10.6. I don't know what it does on 10.5.)

Whichever one you tell to display the dialog, you can tell to activate first, so that's not a big deal. What is a big deal is that on 10.6 I can't get another user's System Events to display a dialog even using sudo.

It's probably better not to explicitly activate either one. The user we're trying to alert is probably in the middle of something, and won't appreciate having keyboard focus yanked away from him peremptorily. If Finder's not in front, it beeps and bounces its icon, but lets the user finish what he was doing. (Imagine a situation where the user is about to press the return key. If we activate Finder (or System Events) and put up a dialog at that precise moment, the user's keypress will dismiss the dialog they didn't have a chance to read.) Of course, they might not appreciate being kicked off the machine either, but at least they get to finish what they were doing. And isn't that, after all, what we're really after? Letting them finish before the machine restarts?

For historical reasons, there's a lot of overlap between Finder and System Events, the primary division of labor being that Finder now focuses on the GUI and foists everything else off onto System Events. Displaying a dialog is definitely GUI, so Finder is the one we should by rights be talking to anyway. Finder's response (beeping and bouncing its icon) is the correct behavior.


All times are GMT -5. The time now is 10:38 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.