0

This launchd daemon is a system daemon (not a user agent) and is designed to run the script file upon wakeup from sleep

the install code:

#!/bin/sh

#find current working directory. store as $curr. use to reference anything in $curr/mysecureview.
curr=$(pwd)

echo "+copy the plist to the system daemons directory."
cp $curr/sleepwatcher/config/sleepwatcher.system.plist /System/Library/LaunchDaemons/sleepwatcher.system.plist

echo "+create the /etc/mysecureview directory to contain all program files."
sudo mkdir /etc/mysecureview

echo "+copy the log file to contain the compiled set of log entries."
sudo cp $curr/log.txt /etc/mysecureview/log.txt

echo "+create the file to contain the individual set of pre-compiled log-entries."
sudo mkdir /etc/mysecureview/logs

echo "+copy the shell script to be used at bootup/wakeup"
sudo cp $curr/sleepwatcher/config/rc.wakeup /etc/mysecureview/rc.wakeup

echo "+move imagesnap"
sudo cp $curr/imagesnap-master/imagesnap /etc/mysecureview/imagesnap

#establishing root ownership of /etc/mysecureview/
#sudo chmod 700 /etc/mysecureview
#echo "+establishing root ownership of /etc/mysecureview/"

echo "========================"
echo "~Installation Succesful~"
echo "========================"

The plist:

<?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>sleepwatcher.system</string>
    <key>ProgramArguments</key>
    <array>
            <string>/usr/local/sbin/sleepwatcher</string>
            <string>-V</string>
            <string>-w /etc/mysecureview/rc.wakeup</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

The script itself:

#!/bin/sh
sudo cd /etc/mysecureview/
sudo ./imagesnap

./imagesnap takes a picture and places it in the same directory. the file is named "snapshot.jpg". I've searched the entire mac, and there isn't any .jpg with this name. I think the issue is with creating or installing the plist, but searching the OSX developer page on launchd isn't much of a help.

Kyle Birch
  • 75
  • 1
  • 10
  • 2
    `sudo cd ...` changes directory and then immediately exits the shell that changed directory. The next `sudo` command starts from the default/initial directory again. – Etan Reisner Jan 20 '16 at 04:33

2 Answers2

2

I see a number of problems here, some fatal, some less serious.

  • As Etan Reisner pointed out, sudo cd doesn't do anything useful because the cd happens in a subprocess. Actually, since the script should be running as root anyway, using sudo is unnecessary. Which is fortunate, because if sudo was needed it wouldn't work because there's nobody there to enter the admin password to authorize it.

  • Custom launch daemons should be installed in /Library/LaunchDaemons, not in /System. El Capitan will block installations in /System; in previous versions it was possible but a bad idea.

  • Speaking of which, there's no error checking anywhere. In El Cap, the cp command that tries to install the daemon in /System/Library/LaunchDaemons will fail, but then the script will run through and announce "~Installation Succesful~". Also, in the script itself you just assume the cd succeeds; you should always check for failure of a cd command, because if it does fail the rest of the script will run in an unexpected with potentially dangerous results.

  • With the RunAtLoad and KeepAlive keys set to true, the daemon will run immediately at startup, and then as soon as it finishes it'll run again and again and again... You need to either change the launch daemon .plist so it only launches the script at appropriate time(s), or make the script itself hang out in the background firing off imagesnap at appropriate times.

  • Daemon labels should be in reverse DNS format, i.e. the label should start with the domain name of the script's developer in reverse order (i.e. apple.com -> com.apple). If you don't have a domain name, I recommend starting it with "local."

  • The daemon won't be loaded until you restart the system. If you want it to be active immediately after installation, add sudo launchctl load /Library/LaunchDaemons/daemonname.plist to the install script (and make sure it runs only if the rest of the installation succeeded).

    You might also want to check whether there's an old version of the daemon already installed, and if so unload it (sudo launchctl unload ...) before replacing it.

  • The arguments passed to the script ("-V" and "-w /etc/mysecureview/rc.wakeup") aren't used by the script; I presume they're intended to be implemented later? If so, you should probably make "-w" and "/etc/mysecureview/rc.wakeup" separate arguments rather than a single argument with a space in the middle.

  • The script itself doesn't do any logging (of errors, success, or anything). This isn't good for general operation, and will make debugging difficult. The best option is to make the script do its own logging, but for debugging it might be easier to add something like <key>StandardOutPath</key><string>/tmp/sleepwatcher.out</string> and <key>StandardErrorPath</key><string>/tmp/sleepwatcher.err</string> to the daemon plist file. Note that changes to the plist won't take effect until you restart the computer, or use sudo launchctl unload and sudo launchctl load on it.

  • The install script finds installer files relative to the current working directory, which is not generally safe -- the CWD is inherited from whatever ran the script, and could be anything. Are you trying to find the installation resources relative to the script's location? If so, it's not all that easy to do reliably; see this previous question.

Community
  • 1
  • 1
Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
0

To execute a script via Launchd on macOS, you need to:

  1. Create a task definition file for your script (.plist)
  2. Put the task file into ~/Library/LaunchAgents
  3. Use Launchctl to manage the task

Since you are not sure whether your script executed successfully or not, you can specify output files in your plist file:

<!-- Output error messages -->
<key>StandardErrorPath</key>
<string>/Users/myname/path/to/stderr.log</string>

<!-- Output messages -->
<key>StandardOutPath</key>
<string>/Users/myname/path/to/stdout.log</string>

To get more detailed information and instructions, you can read this post.

zeck
  • 769
  • 1
  • 7
  • 13