I'm setting up a launchdaemon to run a script that checks if a specific local account is logged in. If that account is logged in, it needs to automatically log back out again. I have a working script, but I can't get a launchagent or launchdaemon to run it.
I've tried it as a launchagent, but that doesn't work, and the specific user is specifically blocked from running scripts. This is running on macOS 10.14.5. It sometimes works when launched by our MDM, but we need it to run even if the MDM is unreachable (thus the local script).
This is my agent so far:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>fubar.plist</string>
<key>ProgramArguments</key>
<array>
<string>/location/of/fubar.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>30</integer>
</dict>
</plist>
And this is the script:
currentUser=$( scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ { print $3 }' )
if [ "$currentUser" == "fubarUser" ]; then
echo "$currentUser is fubarUser. Logging out"
killall loginwindow
fi
I expect it to register that fubarUser has logged in, then echo my message and kill the loginwindow thus logging them out.
If I run the script as root in a terminal window, it correctly identifies whoever is logged in. So I know the script itself works. I just can't get a launchagent or launchdaemon to load it.
In my production version it actually echo's to a log file who it sees is logged in, and that correctly registers the current user.
Turns out it was a permissions problem. We have apparently locked down the permissions on the folder where I was hosting the script. I've since moved it to the /Library/Scripts/ folder and have been able to run it smoothly from there.
Related
I wrote a script to take a picture with my webcam. I want it to run everytime I unlock my mac, so I created a com.example.selfie.plist file in ~/Library/LaunchAgents/. The sh script is working well from a terminal, my plist is working well when I just write text in a file, but I cannot make the imagesnap command to work through the plist file.
selfie.sh
#!/bin/bash
datetime=$(date "+%Y%m%d_%H%M%S")
imagesnap -q -w 2 "/Users/taccle/Documents/Projets/Selfie/Photos/${datetime}.jpg"
com.example.selfie.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.selfie</string>
<key>ProgramArguments</key>
<array>
<string>/Users/taccle/Documents/Projets/Selfie/selfie.sh</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Library/Preferences/com.apple.biometrickitd.plist</string>
</array>
</dict>
</plist>
I suppose the issue is coming from Security and Privacy which doesn't allow launchd to access the camera (I'm not sure how I can get the logs when launchd scripts are running).
I found a workaround but I don't like it so much, my plist file calls run_in_command_line.sh which will open a terminal and then run selfie.sh.
#!/bin/bash
osascript -e 'tell application "Terminal"
do script "/Users/taccle/Documents/Projets/Selfie/selfie.sh; exit"
end tell'
It's working well but I would prefer to have only one script and not starting a terminal like this. Do you know if there's any way to give my launchd access to the camera?
I was looking for an answer to my question on stackoverflow and found a thread (https://superuser.com/questions/229773/run-command-on-startup-login-mac-os-x). That's how I found out about launchd.plist and I made one by myself:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>js.leapmotion</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>open</string>
<string>/Applications/Utilities/Terminal.app</string>
</array>
<key>LaunchOnlyOnce</key>
<true/>
</dict>
</plist>
this indeed starts my terminal after booting my mac. But now I want it to navigate to a directory and run the command gulp in there.
This again will do the rest, opens up a localhost and so on...
So in the end I just need to run gulp within an specific directory. That's all. If launchd.plist is not the best way to go, then I'm open for alternatives.
Otherwise I would like to know how I can tell the terminal what commands it should run.
Thanks for hints.
cheers
J
You can use the open command to open Terminal and run a script by using the -a flag. For example, open -a Terminal /path/to/myscript will open a new Terminal window and run myscript. Note that when myscript finishes, the session will terminate (i.e. there's no shell). To change that, you can run bash or whatever your preferred shell is as part of the script.
In your case, I would suggest creating a basic script to do whatever you want Terminal to execute, such as :
#!/usr/bin/env bash
cd /path/to/your/directory
/usr/bin/gulp
Save that (making sure it's executable), and then change your launchd plist to match:
<key>ProgramArguments</key>
<array>
<string>open</string>
<string>-a</string>
<string>Terminal</string>
<string>/path/to/yourscript</string>
</array>
i am looking for a way to periodically re-launch an application in OS X. since this application has a GUI i chose the LaunchAgent method to do it. the LaunchAgent will call a shell script, which will quit the application (if running) and then open it again.
so far it works, with the only exception that once my called shell script has ended, the launched GUI application is also quit.
i tried opening the application with trailing "&" and using nohup, but no luck.
this is my LaunchAgent (ignore my stupid StartCalendarInterval settings, they are for debugging only):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.mycompany.myapp_relauncher</string>
<key>ProgramArguments</key>
<array>
<string>/Users/xyz/Desktop/myapp_relauncher.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>21</integer>
<key>Minute</key>
<integer>25</integer>
</dict>
</dict>
</plist>
and this is the called script /Users/xyz/Desktop/myapp_relauncher.sh
#!/bin/bash
function log { echo "myapp: "`date "+%Y%m%d-%H%M%S"`" $1" ; logger -t "myapp" "$1" ; }
# stopping the app if running (code ommitted here)
log "starting application now..."
nohup /Applications/myapp.app/Contents/MacOS/myapp &
log "sleeping a few seconds now..."
sleep 10 # the launched applications stays open
log "done sleeping, quitting."
# script ends, launched application ends too
Add <key>AbandonProcessGroup</key><true/> to your LaunchAgent .plist; without that, when the agent (the script) exits launchd "helpfully" cleans up all leftover subprocesses (technically, anything with the same process group ID), like for example the application.
You want to use disown here. This works without closing the application after the script finishes:
#!/bin/bash
/Applications/Adium.app/Contents/MacOS/Adium &
disown
This is because using & just puts the job into the background. Even though it's in the background it is still a child process of the current script, which is killed when its parent process, the script, finishes. By using disown that relationship is removed and it runs on its own.
You might also just use the open command:
killall myapp; open -jga myapp
open -jg usually opens an application hidden and without raising any windows. If for example TextEdit is open but has no open windows, -jg creates and raises a new default window though. To avoid it, you can test if the application is already open:
<key>ProgramArguments</key>
<array>
<string>bash</string>
<string>-c</string>
<string>pgrep -x TextEdit||open -jga TextEdit</string>
</array>
I'm creating a Mac Launch Agent for my app. The Launch agent works fine. But the executable bin file prints some console messages,when the exe is started in terminal and all those messages are logged to Mac Console. How can i skip logging those messages to the Mac Console ..?
I have tried adding a shell script as a Lauch Agent, which starts the exe, so that executable won't log messages to the console. But the script doesn't starts the bin.
This is my Launch Agent plist file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.myapp</string>
<key>Program</key>
<string>./bin/MyBin</string>
<key>WorkingDirectory</key>
<string>/Applications/MyApp/</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
You can override the default treatment of stdout and stderr for launchd jobs by adding the StandardOutPath and StandardErrorPath keys to your .plist file. To discard all output, add this:
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StandardErrorPath</key>
<string>/dev/null</string>
You could also redirect one or both to a log file.
The easiest way is as Gordon Davisson said above. However when i need to start more than one executable, then its possible by shell script.
This was my Script :
#!/bin/bash
cd /Applications/MyApp/
dates=`date`
echo "Exe Started at ::: ${dates}" > proc.log
# Starting Exe
./bin/MyBin 1>/dev/null 2>/dev/null & echo $! > proc.pid
I was having trouble with this script. I can see the proc.log filling up, but no sign of my App. Surprisingly when i removed the '&' from the script ,launch agent started working fine.
./bin/MyBin 1>/dev/null 2>/dev/null & echo $! > proc.pid
Changed to
./bin/MyBin 1>/dev/null 2>/dev/null
I m not sure why Mac is making the background process as a difference in launchd. The Script was & is working fine as it is, when i manually run it.
The output can only be redirected before the process begins. In this case if you don't want to change all your code then the executable for your launch agent will need to be a script. The script can then redirect as needed, e.g.
#!/bin/sh
# redirect to a log file, /dev/null, or wherever it should go;
# this is just an example log file destination
`/usr/bin/dirname $0`/run_real_agent > /tmp/my_agent.$$.log 2>&1
Hello generous computerists!
So I have a launchd plist item that is calling the below shell script every thirty seconds. It checks to see if a program is running and if it isn't, it restarts it. Or at least that is what it's supposed to do.
The problem is, even when the process has been killed, the shell script is stating that the process is still running. I think this is because somehow the boolean is not being reset (Or something along those lines). Any help?
n=`ps -ef | grep Intel | grep -v grep | wc -l`
if [ $n -gt 0 ]
then
echo `date` CURRENTLY RUNNING. >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
else
echo `date` not running. ATTEMPTING RESTART... >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
cd /Library/LaunchAgents/
launchctl load com.Intel.plist
fi
EDIT 1
It has been suggested that adding a 'Keep Alive' argument may be a good solution to my general problem. Any comments?
Here would be my updated plist file which should guarantee that my app keeps running perpetually:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.Intel</string>
<key>OnDemand</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Library/LaunchAgents/Contents/Intel</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
I would love to hear if people think this is correct or not. Thanks so much!
To troubleshoot the immediate problem, try logging the output of the ps command:
processes=`ps -ef | grep [I]ntel`
if [ -n "$processes" ]
then
echo `date` CURRENTLY RUNNING. "$processes" >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
...
I suspect there's something else running (maybe even the script itself) matching Intel; this'll tell you in the log.
However, I think this is irrelevant, because this script seems to be trying to solve a problem that's better solved elsewhere: launchd is entirely capable of monitoring and restarting the processes it manages (it's one of its significant features). Just add
<key>KeepAlive</key>
<true/>
to /Library/LaunchAgents/com.Intel.plist, and launchd will restart the program itself.
BTW, if you for some reason did need to manually restart a launchd-managed process, launchctl load is the wrong incantation -- you want launchd start.