Never been to CodeSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

Test ownership of launchd processes

The following launchd item will execute a simple script every 20 seconds to test or show the ownership of the processes executed by the script. In addition, the script will print out the names and values of its shell environment variables.

To set up the launchd item log in to an admin user account. Use at your own risk.

# LAUNCHD ITEM

/usr/bin/sudo /bin/bash -c '

yourname=$(/usr/bin/logname)
LaunchdPlistFile="/Library/LaunchDaemons/user.${yourname}.launchd.test.plist"
EX_MARK='!'

/bin/cat > "${LaunchdPlistFile}" <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<${EX_MARK}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>Disabled</key>
        <true/>
        <key>Debug</key>
        <true/>


        <key>UserName</key>
        <string>${yourname}</string>
        <key>GroupName</key>
        <string>${yourname}</string>


        <key>EnvironmentVariables</key>
        <dict>
                <key>PATH</key>
                <string>/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin</string>
                <key>YetAnotherEnvironmentVar</key>
                <string>/path/to/dir</string>
        </dict>
        <key>Label</key>
        <string>user.${yourname}.launchd.test</string>
        <key>ProgramArguments</key>
        <array>
                <string>/Users/${yourname}/Desktop/launchd_test.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>ServiceDescription</key>
        <string>Test ownership of launchd processes</string>
        <key>StandardErrorPath</key>
        <string>/Users/${yourname}/Desktop/launchd_test_error.log</string>
        <key>StandardOutPath</key>
        <string>/Users/${yourname}/Desktop/launchd_test.log</string>
        <key>StartInterval</key>
        <integer>20</integer>
        <key>Umask</key>
        <integer>002</integer>
</dict>
</plist>
EOF
'



: <<-'COMMENT'

# switch UserName & GroupName

        <key>UserName</key>
        <string>${yourname}</string>
        <key>GroupName</key>
        <string>${yourname}</string>
or
        <key>UserName</key>
        <string>root</string>
        <key>GroupName</key>
        <string>wheel</string>

or ...

COMMENT


yourname=$(/usr/bin/logname)

LaunchdPlistFile="/Library/LaunchDaemons/user.${yourname}.launchd.test.plist"

open -e "${LaunchdPlistFile}"


# SCRIPT

LaunchdTestScript="/Users/${yourname}/Desktop/launchd_test.sh"

/bin/cat > "${LaunchdTestScript}" <<-'EOF'
#!/bin/bash
# /bin/sh

# cf. man 5 launchd.plist | less -p 'A daemon or agent launched by launchd SHOULD:'
trap '/usr/bin/logger -i "received SIGTERM for launchd test"; exit 1' TERM

# write stdout & stderr to console.log in /Library/Logs/Console/
# open -a Console
# (requires /bin/bash to work correctly!)
#exec >/dev/console 2>&1

echo
echo "SYSTEM LOGS:"
/usr/bin/logger -i "logger:  $0"
/usr/bin/syslog -s -l 1 "syslog:  $0"
echo

echo
echo 'id:'
echo
/usr/bin/id | /usr/bin/sed -E \
   -e $'s/,? /\\\n/g' \
   -e $'/groups=/s/groups=/groups:\\\n/' \
   -e 's/=/ = /g' \
   -e $'s/[()]/   /g'
echo

# cf. man mail | less -p HOME
# cf. Read local Unix mail in Mail.app, http://codesnippets.joyent.com/posts/show/1392
#export HOME=/Users/$(/usr/bin/whoami)
#echo "hello world $(date)" | /usr/bin/mail -s 'test mail' $(/usr/bin/whoami)@localhost

echo
echo "SHELL: $SHELL"
echo "BASH: $BASH"
echo
echo "current set of shell flags: $-"    # cf. help set
echo
echo "SHELLOPTS: $SHELLOPTS"
echo
echo 'set:'
echo
set
echo
printf "%q  %q\n" "IFS:" "$IFS"
echo
echo 'env:'
echo
/usr/bin/env
echo
echo
echo 'shopt ... on:'
echo
shopt | /usr/bin/egrep 'on$'
#set -o | /usr/bin/egrep 'on$'
echo


cd ~
echo "HOME: $PWD"
echo
echo 'try to cd to /private/var/launchd/0'
cd /private/var/launchd/0
return_code=$?
echo "cd exit status: ${return_code}"
echo
if [[ ${return_code} -eq 0 ]]; then echo "ROOT PRIVILEGES"; else echo "NO ROOT PRIVILEGES"; fi
echo

echo "PPID:  $PPID"
echo
echo "PID:  $$"
echo

echo 'ps -p PID:'
echo
/bin/ps -p $PPID
echo
/bin/ps -p $$
echo
echo 'lsof -p PID:'
echo
/usr/sbin/lsof -p $PPID 2>/dev/null
echo
/usr/sbin/lsof -p $$ 2>/dev/null
echo

echo "users:  $(/usr/bin/users)"
echo
echo "groups:  $(/usr/bin/groups)"    # /usr/bin/id -Gn
echo
echo "logname:  $(/usr/bin/logname)"
echo
echo "whoami:  $(/usr/bin/whoami)"   # /usr/bin/id -un


echo; echo
echo "#----------------------------------------------------------------------------------------------- $(date)"
echo; echo

exit 0
#exit 1

EOF



open -e "${LaunchdPlistFile}"
open -e "${LaunchdTestScript}"

/usr/bin/sudo /usr/sbin/chown root:wheel "${LaunchdPlistFile}"
/usr/bin/sudo /bin/chmod 0644 "${LaunchdPlistFile}"

/usr/sbin/chown ${yourname}:${yourname} "${LaunchdTestScript}"
/bin/chmod u+x "${LaunchdTestScript}"

ls -l "${LaunchdPlistFile}"
ls -l "${LaunchdTestScript}"


# enable launchd item
/usr/bin/sudo /bin/launchctl load -w "${LaunchdPlistFile}" 2>/dev/null

# disable launchd item
/usr/bin/sudo /bin/launchctl unload -w "${LaunchdPlistFile}" 2>/dev/null

ls -l /Users/${yourname}/Desktop/launchd_test.log
ls -l /Users/${yourname}/Desktop/launchd_test_error.log

open -a Console /Users/${yourname}/Desktop/launchd_test.log
#/usr/bin/srm -v /Users/${yourname}/Desktop/launchd_test.log

open -a Console /Users/${yourname}/Desktop/launchd_test_error.log


/usr/bin/sudo /bin/launchctl list
/usr/bin/sudo /usr/bin/fs_usage  | /usr/bin/egrep -i launchd_test


# convert possible tabs to spaces
#/usr/bin/expand "${LaunchdPlistFile}" > ~/Desktop/user.${yourname}.launchd.test.plist
#open -e ~/Desktop/user.${yourname}.launchd.test.plist


man 8 launchd
man 5 launchd.plist
man 5 launchd.conf
man 1 launchctl


#----------------------------------------------------------------


# set launchd log level to debug
# cf. http://www.puredarwin.org/developers/booting/launchd
# sudo launchctl log level debug
sudo bash -c 'echo "log level debug" >> /private/etc/launchd.conf'
echo 'log level debug' >> ${HOME}/.launchd.conf

sudo nano /private/etc/launchd.conf
ls -l /private/etc/launchd.conf


# send all launchd logging output to /private/var/log/launchd.log
# cf. http://developer.apple.com/technotes/tn2004/tn2124.html#SECLAUNCHDLOGGING
sudo cp -ip /etc/syslog.conf /etc/syslog.conf-orig
(cat /etc/syslog.conf-orig ; echo "launchd.* /var/log/launchd.log" ) | sudo cp /dev/stdin /etc/syslog.conf
sudo kill -HUP `cat /var/run/syslog.pid`

ls -1 /private/var/log/*log
ls -l /private/var/log/launchd.log

open -a Console /private/var/log/launchd.log


# disable launchd logging

# comment out: "log level debug"
sudo nano /private/etc/launchd.conf
nano ${HOME}/.launchd.conf

# comment out: "launchd.* /var/log/launchd.log"
sudo nano /private/etc/syslog.conf

sudo kill -HUP `cat /var/run/syslog.pid`


Further information on launchd:

- Getting started with launchd
- AFP548: launchd in Depth
- Wikipedia: launchd
- Mac OS Forge: launchd
- PureDarwin: launchd
- Mac OS X Debugging Magic: launchd
- Daemons and Agents
- Daemons and Agents: Execution Contexts
- Daemons and Agents: Hints and Tips
- Mac OS X Server 10.5: Setting a custom umask
- launchd gotcha
- Re: how to run scripts at shutdown - how does launchd shutdown a system?
- Starting PostgreSQL 8.3 through launchd on Mac OS X 10.5.1 Leopard
- The Future of Init, Part IIb: OS X Launchd

Record your dynamic WAN IP addresses

A launchd + shell script exercise to record your DSL router's dynamic WAN IP addresses. Requires some customization on your part. Use at your own risk.

1. create the launchd item in /Library/LaunchDaemons

/usr/bin/sudo /bin/bash -c '

yourname=$(/usr/bin/logname)
LaunchdPlistFile="/Library/LaunchDaemons/net.${yourname}.wanip.update.plist"
EX_MARK='!'

/bin/cat > "${LaunchdPlistFile}" <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<${EX_MARK}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>Disabled</key>
      <true/>
      <key>GroupName</key>
      <string>${yourname}</string>
      <key>Label</key>
      <string>net.${yourname}.wanip.update</string>
      <key>ProgramArguments</key>
      <array>
         <string>/Users/${yourname}/Library/wanip.sh</string>
      </array>
      <key>RunAtLoad</key>
      <true/>
      <key>StartInterval</key>
      <integer>20</integer>
      <key>UserName</key>
      <string>${yourname}</string>
   </dict>
</plist>
EOF
'


#-------------------------


yourname=$(/usr/bin/logname)
LaunchdPlistFile="/Library/LaunchDaemons/net.${yourname}.wanip.update.plist"

open -e "${LaunchdPlistFile}"
ls -l "${LaunchdPlistFile}"

/usr/bin/groups
/usr/bin/sudo /usr/sbin/chown root:wheel "${LaunchdPlistFile}"
#/usr/bin/sudo /usr/sbin/chown root:admin "${LaunchdPlistFile}"
/usr/bin/sudo /bin/chmod 0644 "${LaunchdPlistFile}"

# after creating ~/Library/wanip.sh below
/usr/bin/sudo /bin/launchctl load -w "${LaunchdPlistFile}" 2>/dev/null
#/usr/bin/sudo /bin/launchctl unload -w "${LaunchdPlistFile}" 2>/dev/null

/usr/bin/sudo /bin/launchctl list
/usr/bin/sudo /usr/bin/fs_usage | /usr/bin/egrep -i wanip


2. create a shell script that will be run by the launchd item at the specified intervals in seconds (here: every 20 seconds)

Version 1:
#!/bin/bash

# Version 1 with two columns (date, IP address)
# cat ~/Library/wanip.sh   (/Users/yourname/Library/wanip.sh)
# /usr/sbin/chown $(/usr/bin/logname):$(/usr/bin/logname) ~/Library/wanip.sh
# /bin/chmod 0744 ~/Library/wanip.sh

declare last_line_closed last_line_offline last_line_unreachable newfile old_wanip time wanip

declare IF='en0'
declare wanip_record_file="/Users/YOURLOGNAME/Library/wanip_record.txt"

# try to find your router_wanip_site by surfing to the IP addresses returned by the following commands:
# route -n get default | egrep interface | awk '{print $NF}'
# ipconfig getoption en0 router
# ipconfig getoption en0 domain_name_server

declare router_wanip_site='http://xxxx.xx/xxx.htm'
#declare router_wanip_site='http://checkip.dyndns.org'   # alternative


/bin/sleep 3

/usr/sbin/ipconfig waitall

if [[ "$(/sbin/route -n get default | /usr/bin/egrep interface | /usr/bin/awk '{print $NF}')" == "${IF}" ]]; then

   /usr/bin/curl -I -L -s --max-time 10 "${router_wanip_site}" 1>/dev/null
 
   if [[ $? -ne 0 ]]; then 
      time="$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"
      /usr/bin/logger -i "${time}     router_wanip_site is unreachable for wanip.sh"
      last_line_unreachable="$(/usr/bin/sed -E -n -e '$,$s/^.+ (unreachable).*$/\1/p' "${wanip_record_file}")"
      if [[ -n "$last_line_unreachable" ]]; then exit 0; fi
      echo "${time}          router_wanip_site is unreachable" >> "${wanip_record_file}"
      exit 0
   fi


   # match first IP address with egrep
   wanip="$(/usr/bin/curl -L -s --max-time 10 "${router_wanip_site}" | \
              /usr/bin/egrep -o -m 1 ' ([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}')"
   wanip="${wanip// /}"

   # alternative with sed for matching a line with a characteristic string plus IP address
   #wanip="$(/usr/bin/curl -L -s --max-time 10 "${router_wanip_site}" | \
              #/usr/bin/sed -E -n -e '/STRING: /{s/^.+ ([[:digit:]\.]+).*$/\1/p;q;}')"


   time="$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"

   if [[ -n "${wanip}" ]]; then 
      old_wanip="$(/usr/bin/sed -E -n -e '$,$s/^.+ ([[:digit:]\.]+).*$/\1/p' "${wanip_record_file}")"
      if [[ "${wanip}" == "${old_wanip}" ]]; then exit 0; fi
      echo "${time}          ${wanip}" >> "${wanip_record_file}"
   else
      last_line_closed="$(/usr/bin/sed -E -n -e '$,$s/^.+ (closed).*$/\1/p' "${wanip_record_file}")"
      if [[ -n "${last_line_closed}" ]]; then exit 0; fi
      echo "${time}          connection closed" >> "${wanip_record_file}"
   fi

else

   last_line_offline="$(/usr/bin/sed -E -n -e '$,$s/^.+ (offline).*$/\1/p' "${wanip_record_file}")"
   if [[ -n "$last_line_offline" ]]; then exit 0; fi
   time="$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"
   echo "${time}          offline" >> "${wanip_record_file}"

fi

if [[ $(/usr/bin/stat -f %z "${wanip_record_file}") -gt 31457280 ]]; then
   newfile="${wanip_record_file}-$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"
   /bin/mv "${wanip_record_file}" "${newfile}"
fi

exit 0


Version 2:
#!/bin/bash

# Version 2 has an additional $name column
# cat ~/Library/wanip.sh   (/Users/yourname/Library/wanip.sh)
# /usr/sbin/chown $(/usr/bin/logname):$(/usr/bin/logname) ~/Library/wanip.sh
# /bin/chmod 0744 ~/Library/wanip.sh

declare format last_line_closed last_line_offline last_line_unreachable name newfile old_name old_wanip time wanip

declare IF='en0'
declare wanip_record_file="/Users/YOURLOGNAME/Library/wanip_record.txt"

# try to find your router_wanip_site by surfing to the IP addresses returned by the following commands:
# route -n get default | egrep interface | awk '{print $NF}'
# ipconfig getoption en0 router
# ipconfig getoption en0 domain_name_server

declare router_wanip_site='http://xxxx.xx/xxx.htm'
#declare router_wanip_site='http://checkip.dyndns.org'   # alternative

name="$(/usr/bin/who | /usr/bin/awk '/console/ {print $1}')"
name="${name//[[:cntrl:]]/,}"
if [[ -z "${name}" ]]; then name='[logout]'; fi

old_name="$(/usr/bin/sed -E -n -e '$,$s/^[^ ]+ +([^ ]+) +[^ ].*$/\1/p' "${wanip_record_file}")"

format='%-35s%-20s%-20s\n'   # for printf

#/bin/sleep 3

/usr/sbin/ipconfig waitall

if [[ "$(/sbin/route -n get default | /usr/bin/egrep interface | /usr/bin/awk '{print $NF}')" == "${IF}" ]]; then

   /usr/bin/curl -I -L -s --max-time 10 "${router_wanip_site}" 1>/dev/null
 
   if [[ $? -ne 0 ]]; then 
      time="$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"
      /usr/bin/logger -i "${time}     router_wanip_site is unreachable for wanip.sh"
      last_line_unreachable="$(/usr/bin/sed -E -n -e '$,$s/^.+ (unreachable).*$/\1/p' "${wanip_record_file}")"
      if [[ -n "$last_line_unreachable" ]]; then 
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${format}" "${time}" "${name}" "router_wanip_site is unreachable" >> "${wanip_record_file}"
         fi
         exit 0
      fi
      printf "${format}" "${time}" "${name}" "router_wanip_site is unreachable" >> "${wanip_record_file}"
      exit 0
   fi


   # match first IP address with egrep
   wanip="$(/usr/bin/curl -L -s --max-time 10 "${router_wanip_site}" | \
              /usr/bin/egrep -o -m 1 ' ([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}')"
   wanip="${wanip// /}"

   # alternative with sed for matching a line with a characteristic string plus IP address
   #wanip="$(/usr/bin/curl -L -s --max-time 10 "${router_wanip_site}" | \
              #/usr/bin/sed -E -n -e '/STRING: /{s/^.+ ([[:digit:]\.]+).*$/\1/p;q;}')"


   time="$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"

   if [[ -n "${wanip}" ]]; then 
      old_wanip="$(/usr/bin/sed -E -n -e '$,$s/^.+ ([[:digit:]\.]+).*$/\1/p' "${wanip_record_file}")"
      if [[ "${wanip}" == "${old_wanip}" ]]; then
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${format}" "${time}" "${name}" "${wanip}" >> "${wanip_record_file}"
         fi
         exit 0
      fi

      printf "${format}" "${time}" "${name}" "${wanip}" >> "${wanip_record_file}"
   else
      last_line_closed="$(/usr/bin/sed -E -n -e '$,$s/^.+ (closed).*$/\1/p' "${wanip_record_file}")"
      if [[ -n "${last_line_closed}" ]]; then 
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${format}" "${time}" "${name}" "connection closed" >> "${wanip_record_file}"
         fi
         exit 0
      fi
      printf "${format}" "${time}" "${name}" "connection closed" >> "${wanip_record_file}"
   fi

else

   last_line_offline="$(/usr/bin/sed -E -n -e '$,$s/^.+ (offline).*$/\1/p' "${wanip_record_file}")"
   time="$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"
   if [[ -n "$last_line_offline" ]]; then 
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${format}" "${time}" "${name}" "offline" >> "${wanip_record_file}"
         fi
      exit 0
   fi
   printf "${format}" "${time}" "${name}" "offline" >> "${wanip_record_file}"

fi


if [[ $(/usr/bin/stat -f %z "${wanip_record_file}") -gt 31457280 ]]; then
   newfile="${wanip_record_file}-$(/bin/date +%Y-%m-%d-%H.%M.%S-%Z)"
   /bin/mv "${wanip_record_file}" "${newfile}"
fi

exit 0


Version 3:
/usr/bin/sudo /bin/bash -c '

yourname=$(/usr/bin/logname)
LaunchdPlistFile="/Library/LaunchDaemons/net.${yourname}.wanip.update.plist"
EX_MARK='!'

/bin/cat > "${LaunchdPlistFile}" <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<${EX_MARK}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>Disabled</key>
        <true/>
        <key>GroupName</key>
        <string>${yourname}</string>
        <key>Label</key>
        <string>net.${yourname}.wanip.update</string>
        <key>ProgramArguments</key>
        <array>
            <string>/Users/${yourname}/Library/wanip.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>UserName</key>
        <string>${yourname}</string>
</dict>
</plist>
EOF
'


#----------------------------------------------


yourname=$(/usr/bin/logname)
LaunchdPlistFile="/Library/LaunchDaemons/net.${yourname}.wanip.update.plist"

open -e "${LaunchdPlistFile}"
ls -l "${LaunchdPlistFile}"

/usr/bin/groups
/usr/bin/sudo /usr/sbin/chown root:wheel "${LaunchdPlistFile}"
#/usr/bin/sudo /usr/sbin/chown root:admin "${LaunchdPlistFile}"
/usr/bin/sudo /bin/chmod 0644 "${LaunchdPlistFile}"

# after creating ~/Library/wanip.sh below
/usr/bin/sudo /bin/launchctl load -w "${LaunchdPlistFile}" 2>/dev/null
#/usr/bin/sudo /bin/launchctl unload -w "${LaunchdPlistFile}" 2>/dev/null

/usr/bin/sudo /bin/launchctl list
/usr/bin/sudo /usr/bin/fs_usage | /usr/bin/egrep -i wanip


#-----------------------------------------------------------------------------------------------------


#!/bin/bash

# Version 3 is started only once by the launchd item and records shutdown processes
# Inspired by: "Re: how to run scripts at shutdown - how does launchd shutdown a system?", 
#              http://lists.apple.com/archives/macos-x-server/2007/Oct/msg00021.html
# cat ~/Library/wanip.sh   (/Users/yourname/Library/wanip.sh)
# /usr/sbin/chown $(/usr/bin/logname):$(/usr/bin/logname) ~/Library/wanip.sh
# /bin/chmod 0744 ~/Library/wanip.sh

declare last_line_closed last_line_offline last_line_unreachable name 
declare newfile old_name old_wanip printf_format time time_format wanip

declare IF='en0'
declare wanip_record_file="/Users/YOURLOGNAME/Library/wanip_record.txt"

# try to find your router_wanip_site by surfing to the IP addresses returned by the following commands:
# route -n get default | egrep interface | awk '{print $NF}'
# ipconfig getoption en0 router
# ipconfig getoption en0 domain_name_server

declare router_wanip_site='http://xxxx.xx/xxx.htm'
#declare router_wanip_site='http://checkip.dyndns.org'   # alternative


WHILEVAR=1
TRAPSIGNAL=

function exit_function() {
   TRAPSIGNAL='yes'
   # $! holds the PID of last process that has been started in the background (cmd &)
   [[ $! -gt $$ ]] && kill -TERM $!
}

trap exit_function SIGHUP SIGINT SIGTERM


time_format='+%Y-%m-%d--%H.%M.%S--%Z'
printf_format='%-40s%-20s%-20s\n'


while [[ ${WHILEVAR} ]]; do

   name="$(/usr/bin/who | /usr/bin/awk '/console/ {print $1}')"
   name="${name//[[:cntrl:]]/,}"
   if [[ -z "${name}" ]]; then name='[logout]'; fi
   old_name="$(/usr/bin/sed -E -n -e '$,$s/^[^ ]+ +([^ ]+) +[^ ].*$/\1/p' "${wanip_record_file}")"
   /usr/sbin/ipconfig waitall

   /bin/sleep 20 &     # time interval
   wait $!

   if [[ ${TRAPSIGNAL} ]]; then
      time="$(/bin/date ${time_format})"
      printf "${printf_format}" "${time}" "${name}" "shutdown" >> "${wanip_record_file}"
      exit 0
   fi


if [[ "$(/sbin/route -n get default | /usr/bin/egrep interface | /usr/bin/awk '{print $NF}')" == "${IF}" ]]; then

   /usr/bin/curl -I -L -s --max-time 10 "${router_wanip_site}" 1>/dev/null
 
   if [[ $? -ne 0 ]]; then 
      time="$(/bin/date ${time_format})"
      /usr/bin/logger -i "${time}     router_wanip_site is unreachable for wanip.sh"
      last_line_unreachable="$(/usr/bin/sed -E -n -e '$,$s/^.+ (unreachable).*$/\1/p' "${wanip_record_file}")"
      if [[ -n "$last_line_unreachable" ]]; then 
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${printf_format}" "${time}" "${name}" "router_wanip_site is unreachable" >> "${wanip_record_file}"
         fi
         continue
      fi
      printf "${printf_format}" "${time}" "${name}" "router_wanip_site is unreachable" >> "${wanip_record_file}"
      continue
   fi


   # match first IP address with egrep
   wanip="$(/usr/bin/curl -L -s --max-time 10 "${router_wanip_site}" | \
              /usr/bin/egrep -o -m 1 ' ([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}')"
   wanip="${wanip// /}"

   # alternative with sed for matching a line with a characteristic string plus IP address
   #wanip="$(/usr/bin/curl -L -s --max-time 10 "${router_wanip_site}" | \
              #/usr/bin/sed -E -n -e '/STRING: /{s/^.+ ([[:digit:]\.]+).*$/\1/p;q;}')"


   time="$(/bin/date ${time_format})"

   if [[ -n "${wanip}" ]]; then 
      old_wanip="$(/usr/bin/sed -E -n -e '$,$s/^.+ ([[:digit:]\.]+).*$/\1/p' "${wanip_record_file}")"
      if [[ "${wanip}" == "${old_wanip}" ]]; then
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${printf_format}" "${time}" "${name}" "${wanip}" >> "${wanip_record_file}"
         fi
         continue
      fi
      printf "${printf_format}" "${time}" "${name}" "${wanip}" >> "${wanip_record_file}"
   else
      last_line_closed="$(/usr/bin/sed -E -n -e '$,$s/^.+ (closed).*$/\1/p' "${wanip_record_file}")"
      if [[ -n "${last_line_closed}" ]]; then 
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${printf_format}" "${time}" "${name}" "connection closed" >> "${wanip_record_file}"
         fi
         continue
      fi
      printf "${printf_format}" "${time}" "${name}" "connection closed" >> "${wanip_record_file}"
   fi

else

   last_line_offline="$(/usr/bin/sed -E -n -e '$,$s/^.+ (offline).*$/\1/p' "${wanip_record_file}")"
   time="$(/bin/date ${time_format})"
   if [[ -n "$last_line_offline" ]]; then 
         if [[ "${name}" != "${old_name}" ]]; then
            printf "${printf_format}" "${time}" "${name}" "offline" >> "${wanip_record_file}"
         fi
      continue
   fi
   printf "${printf_format}" "${time}" "${name}" "offline" >> "${wanip_record_file}"

fi


if [[ $(/usr/bin/stat -f %z "${wanip_record_file}") -gt 31457280 ]]; then
   newfile="${wanip_record_file}-$(/bin/date ${time_format})"
   /bin/mv "${wanip_record_file}" "${newfile}"
fi

done

exit 0

Using PlistBuddy to customize syslogd


# Inspired by: http://www.maciverse.com/the-case-of-the-slow-mac-and-how-to-fix-it.html

# cf. man syslog, man syslogd and http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/syslogd.8.html
/usr/bin/open -a Console   # system.log
/usr/bin/tail -n 50 /private/var/log/system.log

help declare
declare -x sudo=/usr/bin/sudo plistbuddy=/usr/libexec/PlistBuddy defaults=/usr/bin/defaults
/usr/bin/env | /usr/bin/grep -E 'sudo=|plistbuddy=|defaults='

# create a symbolic link (on Mac OS X 10.4)
help test
/usr/bin/locate PlistBuddy
if [[ ! -e /usr/libexec/PlistBuddy ]]; then $sudo /bin/ln -s "/Library/Receipts/AdditionalEssentials.pkg/Contents/Resources/PlistBuddy" /usr/libexec/PlistBuddy; fi

# make a backup
$sudo /bin/cp -p /System/Library/LaunchDaemons/com.apple.syslogd.plist /System/Library/LaunchDaemons/com.apple.syslogd.plist.orig

# cf. http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/PlistBuddy.8.html
$plistbuddy -h   

$plistbuddy -c Print /System/Library/LaunchDaemons/com.apple.syslogd.plist
$plistbuddy -c "Print :ProgramArguments" /System/Library/LaunchDaemons/com.apple.syslogd.plist

# compare
$defaults read /System/Library/LaunchDaemons/com.apple.syslogd
$defaults read /System/Library/LaunchDaemons/com.apple.syslogd ProgramArguments

$sudo /usr/bin/nano /System/Library/LaunchDaemons/com.apple.syslogd.plist

$sudo $plistbuddy -c "Delete :ProgramArguments" /System/Library/LaunchDaemons/com.apple.syslogd.plist
$sudo $plistbuddy -c "Add :ProgramArguments array" /System/Library/LaunchDaemons/com.apple.syslogd.plist
$sudo $plistbuddy -c "Add :ProgramArguments:0 string '/usr/sbin/syslogd'" /System/Library/LaunchDaemons/com.apple.syslogd.plist
$sudo $plistbuddy -c "Add :ProgramArguments:1 string '-c'" /System/Library/LaunchDaemons/com.apple.syslogd.plist
$sudo $plistbuddy -c "Add :ProgramArguments:2 integer 3" /System/Library/LaunchDaemons/com.apple.syslogd.plist

# Mac OS X 10.5
#$sudo $plistbuddy -c "Add :ProgramArguments:3 string '-a'" /System/Library/LaunchDaemons/com.apple.syslogd.plist
#$sudo $plistbuddy -c "Add :ProgramArguments:4 string '-db_max'" /System/Library/LaunchDaemons/com.apple.syslogd.plist
#$sudo $plistbuddy -c "Add :ProgramArguments:5 integer 5000000" /System/Library/LaunchDaemons/com.apple.syslogd.plist

$plistbuddy -c "Print :ProgramArguments" /System/Library/LaunchDaemons/com.apple.syslogd.plist
$defaults read /System/Library/LaunchDaemons/com.apple.syslogd ProgramArguments
$sudo /usr/bin/nano /System/Library/LaunchDaemons/com.apple.syslogd.plist

# reset com.apple.syslogd.plist
#if [[ -n $(/usr/bin/sw_vers -productVersion | /usr/bin/grep '^10.5') ]]; then exit; fi   # exit if on Mac OS X 10.5.x
$sudo /bin/rm -f /System/Library/LaunchDaemons/com.apple.syslogd.plist
$sudo /bin/cp -p /System/Library/LaunchDaemons/com.apple.syslogd.plist.orig /System/Library/LaunchDaemons/com.apple.syslogd.plist

$sudo /usr/bin/nano /System/Library/LaunchDaemons/com.apple.syslogd.plist

# restart syslogd
#$sudo /bin/launchctl unload -w /System/Library/LaunchDaemons/com.apple.syslogd.plist 2>/dev/null
#/bin/sleep 3
#$sudo /bin/launchctl load -w /System/Library/LaunchDaemons/com.apple.syslogd.plist 2>/dev/null
#$sudo /usr/bin/killall -HUP syslogd   # alternative

Automated virus scanning with ClamAV on Mac OS X 10.4

Author: jv
License: The MIT License, Copyright (c) 2008 jv
Description: basic setup to scan files added to specified directories automatically for viruses using ClamAV; for instructions on how to run ClamAV from a system service agent account (non-root) see here; use at your own risk
Platform: Mac OS X 10.4.11 Client
Requirements: sudo port install clamav (after installing MacPorts); to fix the command search path, insert the following statement at the end of your ~/.bash_login file: export PATH="/opt/local/bin:/opt/local/sbin:$PATH" and then: source ~/.bash_login



# download ClamAV
sudo port install clamav      # requires open firewall port 873
#sudo port uninstall clamav

man clamd
man clamd.conf
man clamdscan
man clamscan
man freshclam


# configure /opt/local/etc/freshclam.conf

sudo cp -p /opt/local/etc/example-freshclam.conf /opt/local/etc/freshclam.conf
sudo sed -i "" -e 's/^Example/#Example/' /opt/local/etc/freshclam.conf              # comment out 'Example' line
#sudo sed -i "" -e 's/^#Example/Example/' /opt/local/etc/freshclam.conf              # uncomment 'Example' line
sudo nano /opt/local/etc/freshclam.conf


# make sure you are a member of the wheel and admin group
id -G -n $(whoami) | grep -Eo 'wheel|admin'
dseditgroup -o checkmember -m $(whoami) wheel; echo $?
dseditgroup $(whoami)
dseditgroup wheel
dseditgroup admin

sudo dscl . -append /Groups/wheel GroupMembership $(whoami)      # add user to group if necessary
#sudo dseditgroup -o edit -a $(whoami) -t user wheel             # add user to group
#sudo dscl . -delete /Groups/wheel GroupMembership $(whoami)     # delete user from group
#sudo dseditgroup -o edit -d $(whoami) -t user wheel             # delete user from group


sudo chown -R root:wheel /opt/local/share/clamav  
sudo chmod -R 0770 /opt/local/share/clamav

freshclam       # update virus database

# test some clamav commands
clamscan /path/to/file
sudo clamscan -r /tmp
sudo clamscan -r /private/var/tmp
clamscan -r ~/Library/Caches
clamscan -r ~/Library/Caches/java
sudo clamscan -r ~/Library/Mail
clamscan -r ~/Library


# configure /opt/local/etc/clamd.conf
# open /opt/local/etc
# sudo nano /opt/local/etc/clamd.conf
# cf. http://www.silvester.org.uk/OSX/configuring_clamd.html

sudo cp -p /opt/local/etc/clamd.conf /opt/local/etc/clamd.conf.orig

sudo sh -c '
cat << EOF > /opt/local/etc/clamd.conf
LogFile /private/var/log/clamd.log
LogFileMaxSize 10M
LogTime yes
TemporaryDirectory /private/var/tmp
DatabaseDirectory /opt/local/share/clamav
LocalSocket /tmp/clamd
FixStaleSocket yes
TCPAddr 127.0.0.1
MaxConnectionQueueLength 30
MaxThreads 20
ExitOnOOM yes
ScanOLE2 yes  # Microsoft Office documents and .msi files
ScanPDF yes
ArchiveMaxFileSize 100M
ArchiveMaxCompressionRatio 0
#VirusEvent echo virus: %v >> /path/to/file.txt
EOF
'

sudo chown root:wheel /opt/local/etc/clamd.conf
sudo chmod 750 /opt/local/etc/clamd.conf



Create the launchd item /Library/LaunchDaemons/net.clamav.clamd.plist


sudo nano /Library/LaunchDaemons/net.clamav.clamd.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