Skip to content

Launching Custom Daemons Using launchd

In OSX I needed a shell script to execute at login. There are a few different ways to perform this so I thought it might be helpful to document what your options are. This is the shell script I will execute:

#!/bin/bash

function start() {
    echo ${PATH}
    echo "start mkdocs"
    # It should not append a & symbol to the end as urual to run the command in the background, cause we will let launch to take over the task.
    /Library/Frameworks/Python.framework/Versions/3.10/bin/mkdocs serve 

}

function stop() {
    echo "stop mkdocs client..."
  ps -ef | grep "mkdocs" | awk  '{ print $2 }' | xargs  kill 
}

case ${1} in
  "start")
    start
  ;;
  "stop")
    stop    
  ;;
  "restart")
    stop
    sleep 3
    start
  ;;
  "")
    start   
  ;;

  *)
  echo "error arguents"
  exit 1
  ;;
esac

This script was named "blogserver.sh" locating in my blog diractory "\~/wk/blog/". It start my blogserver, so that I can browse my blogs located in my own cumputer in the browser. It should be noted that the services programe you are going to excute should not append a & symbol to the end as urual to daemonize , cause we will let launchd to take over the task. If you do this way, launchd will lose track of it and attempt to relaunch it.

The interface to launchd is a tool called launchctl which allows for loading and unloading daemons into launchd. XML formatted plist files are used to describe operations loaded into launchctl.

<?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>mkdocs.blogs</string>
    <key>ProgramArguments</key>
    <array>
      <string>./blogserver.sh</string>
      <string>start</string>
    </array>
    <key>WorkingDirectory</key>
    <string>/Users/wzq/wk/blog</string>
    <key>RunAtLoad</key>
    <true />
    <key>StandardErrorPath</key>
    <string>/Users/wzq/Library/Logs/myblogs.log</string>
    <key>StandardOutPath</key>
    <string>/Users/wzq/Library/Logs/myblogs.log</string>
  </dict>
</plist>

The above file mkdocs.blogs.plist needs to be saved in the ~/Library/LaunchAgents directory. As you can see the xml dictates that the "blogserver.sh" file should be executed at load, note we no longer need a ".command" file extension. We will now use launchctl to load our plist file.

 launchctl load ~/Library/LaunchAgents/mkdocs.blogs.plist

To verify that your script executed correctly lets ask launchctl to show us what is running.

launchctl list | grep "mkdocs.blogs"

You will likely see an entries with three columns. Mine looks like this:

758 0   mkdocs.blogs

The first column is the process id. The second column displays the last exit status of the job, zero represent success.

Property list

A list of often used keys follows below. All keys are optional unless otherwise noted. For a full list, see Apple's manpage for launchd.plist.

Key Type Description
Label String The name of the job. By convention, the job label is the same as the plist file name, without the .plist extension. Required.
Program String A path to an executable. Useful for simple launches. At least one of Program or ProgramArguments is required.
ProgramArguments Array of strings An array of strings representing a UNIX command. The first string is generally a path to an executable, while latter strings contain options or parameters. At least one of Program or ProgramArguments is required.
UserName String
(defaults to root or current user)
The job will be run as the given user, who may (or may not) be the user who submitted it to launchd.
RunAtLoad Boolean
(defaults to NO)
A boolean flag that defines if a task is launched immediately when the job is loaded into launchd.
StartOnMount Boolean
(defaults to NO)
A boolean flag that defines if a task is launched when a new filesystem is mounted.
QueueDirectories Array of strings Watch a directory for new files. The directory must be empty to begin with, and must be returned to an empty state before QueueDirectories will launch its task again.
WatchPaths Array of strings Watch a filesystem path for changes. Can be a file or folder.
StartInterval Integer Schedules job to run on a repeating schedule. Indicates number of seconds to wait between runs.
StartCalendarInterval Dictionary of integers or Array of dictionaries of integers Job scheduling. The syntax is similar to cron.
RootDirectory String The job will be chrooted into this directory before execution.
WorkingDirectory String The job will be chdired into this directory before execution.
StandardInPath,
StandardOutPath,
StandardErrorPath
String Keys to determine files for input and output for the launched process.
LowPriorityIO Boolean Tells the kernel that this task is of a low priority when doing filesystem I/O.
AbandonProcessGroup Boolean
(defaults to NO)
A boolean flag that defines whether subprocesses launched from a task launched by launchd will be killed when the task ends. Useful where a short-lived task starts a long-lived subtask, but may result in zombie processes.
SessionCreate Boolean
(defaults to NO)
A boolean flag that defines whether a security session will be created for the task and its subprocesses.

Reference

\