How can a background shell script find out who the active, current user is?

Discussion in 'macOS' started by timshead, Aug 31, 2008.

  1. timshead macrumors newbie

    Joined:
    Aug 31, 2008
    #1
    Let me explain what I'm trying to do before I get to my question. I'm trying to create a shell script for my Mac, OS 10.5.4, that does the following:

    -Runs every 20 seconds
    -Checks to see if a user is logged in and active
    -Captures a screenshot of that user's desktop and saves it to disk

    I figure out how to make the script run every 20 seconds by using launchctl along with a plist file. The plist file uses the StartInterval key with a value of 20, thus invoking it every 20 seconds. I loaded the job as root with the command "sudo launchtl load $path_to_plist_file", then "sudo load $name_of_job".

    I figured out how to capture a screenshot with a script. Since the script is running AS root but it is not grabbing a screenshot FOR root, according to the screencapture man page I have to use the command "sudo launchctl bsexec $PID screencapture..." I have tested this and it works, but it only works if I know the PID for the current, active user.

    I do not know how to find the PID for the current, active user.

    As I said above, I would like the script to see first of all IF there is a user logged in with their desktop open. Since I have Fast User Switching enabled, there can be multiple users logged in but not active and the monitor displaying the login window. Also, the script is running as root so I can't use "whoami" or "logname" because they won't tell me anything about which user is using their desktop.

    Does anyone know how a script can check to see if a user is logged in with their desktop active on the monitor?
     
  2. bankshot macrumors 65816

    bankshot

    Joined:
    Jan 23, 2003
    Location:
    Southern California
    #2
    I wanted to do the same thing a while back (it's a custom script that checks a server to determine if the laptop is stolen, and sends data if it is), and I ended up solving it using a little AppleScript magic. I didn't even think to look at the screencapture man page. Silly me. :rolleyes:

    Basically, I created an AppleScript with the following contents:

    Code:
    set cmd to "/usr/sbin/screencapture -x -tjpg /tmp/screen.jpg > /dev/null 2>&1"
    do shell script cmd
    Of course you can change the screencapture options and the path of the resulting image file if you want. In Script Editor, save this as an application bundle, with none of the options checked.

    You probably want to make it a background application so the user doesn't notice the script launching. To do this, go to the application bundle in Finder, right-click and Show Package Contents, then go to Contents and open Info.plist with TextEdit. Just above the line with <key>WindowState</key> insert the following:

    Code:
    	<key>NSUIElement</key>
    	<string>1</string>
    
    Finally, in your main shell script, call this with "open /path/to/AppleScriptBundle.app". This opens it as the current logged-in user without you having to guess who that is. ;)

    Hopefully this helps. I suppose the only thing it doesn't do is check whether somebody is actually active on the machine.
     
  3. timshead thread starter macrumors newbie

    Joined:
    Aug 31, 2008
    #3
    But if I'm running a shell script using launchctl, then it will not in fact open it as the current logged-in user, it will run it as root because I initiated it with the command "launchctl start $job_name".

    But that gives me an idea; can I set launchctl to run the script as the current logged-in user?

    Thanks for the idea.
     
  4. timshead thread starter macrumors newbie

    Joined:
    Aug 31, 2008
    #4
    I think what I'm trying to do may not be entirely possible. Here's a couple of blurbs from Apple's document "Supporting Fast User Switching" at http://developer.apple.com/documentation/MacOSX/Conceptual/BPMultipleUsers/Concepts/FastUserSwitching.html

    ...and finally, from "User Switch Notifications"

    So I think what happens is loginwindow handles logging a user in, launching their dock and finder, etc. If a user switch occurs, an event is sent out to all apps in the login session that is deactivated and to the apps in the login session that is activated.

    I think I'd have to create an actual application that starts up for each user when they login, accesses the Core Graphics Framework to get their username, and registers to receive the activation/deactivation events so it only generates screenshots while the user is active.

    I am going to go another route based on what I've figured out. I am going to make my script run for each user when they login, then continue to run in the background no matter if they are active or not. I will make the script limit the number of screenshots it captures and I will make it store each user's screenshots in a separate folder.

    If I am wrong about what I said above and it turns out there IS some way to do what I was trying to do, by all means let me know, but I think this will prove to be the easiest way to make my script work.
     
  5. bankshot macrumors 65816

    bankshot

    Joined:
    Jan 23, 2003
    Location:
    Southern California
    #5
    My script runs from cron, which in OS X is effectively called by launchctl. I'm running it as root. When root runs the "open" command, the resulting application is run as the currently logged-in user. You can try it: just ssh in to the machine and run something like "sudo open /Applications/iTunes.app". Even though "open" runs as root, iTunes will start as the logged-in user. This is exactly the situation you want for running screencapture.

    I wouldn't have suggested that solution if it didn't work for me. ;)
     
  6. timshead thread starter macrumors newbie

    Joined:
    Aug 31, 2008
    #6
    My bad. I see that your method does indeed work. It seems to use more system resources to launch the application; even though it is launching in the background I can tell *something* is going on, whereas with the script I couldn't tell that something was going on.

    I think I am still going to try my second option, which is to use launchctl to run the script for each user upon login and continue to run until the user logs out. I'll post an update if/when I get this working.

    My one concern with doing this via launchctl is that if the computer is put to sleep the launchctl events are queued up and run sequentially when the computer is turned back on. That could lead to a pretty severe performance hit if the computer is put to sleep for any period of time. I guess I'll just have to see what kind of impact it has.
     
  7. timshead thread starter macrumors newbie

    Joined:
    Aug 31, 2008
  8. Detektiv-Pinky macrumors 6502a

    Detektiv-Pinky

    Joined:
    Feb 25, 2006
    Location:
    Berlin, Germany
    #8
    $ man who
     
  9. timshead thread starter macrumors newbie

    Joined:
    Aug 31, 2008
    #9
    Wow, so helpful. I read that, I don't think you read my question. If you did, perhaps you know how to use "who" to do what I'm trying to do. "Who" doesn't tell you which user is active, just which users are logged in.
     
  10. jasonrm macrumors member

    jasonrm

    Joined:
    Jan 26, 2008
    Location:
    Arizona, U.S.A.
    #10
    My apologies for digging up an old thread, but since I was unable to find a suitable solution (here and elsewhere), I threw together a solution. Since it's possible that others still might come across this thread, I figured that adding it here might be helpful.

    Anyhow… here's the solution I quickly threw together. It's just a small utility called activeUser that's based on Apple's developer documentation.

    So, the SystemConfiguration framework provided by Apple gives applications access to the current "Console User" via a C call to SCDynamicStoreCopyConsoleUser. Other methods like who(1) and last(1) give lots of info about who might be logged in, but they don't specify which user is actually active. Active being defined as the currently logged in user. A user will be considered the current console user even if the screen saver is active. To further clarify, if a user has previously logged in, but has been "fast user switched" to the background, then that user is not the current console user.

    All it does it get what Apple calls the "current console user", and returns the short username for that user, of if at the login screen it returns none. (Which could be a problem if you have a user named none, but if that's the case you might have bigger issues.)

    Tested only on Mac OS X 10.6, but should work on 10.3+ (maybe even back to 10.1, however I've only compiled for 10.3+)

    edit:
    Of course, as soon as I post this, I find another option,
    Code:
    stat /dev/console
    which if you parse it, you should be able to find the current console user. I'm not inclined to go this route as Apple might change this behavior and I hate parsing output of unix commands. ;)
     
  11. BlueRevolution macrumors 603

    BlueRevolution

    Joined:
    Jul 26, 2004
    Location:
    Montreal, QC
    #11
    Actually, that's exactly the command you should use. Specifically:

    who am i

    I'm reviving this thread because I needed an answer to the same question and came here.
     

Share This Page