How to Create a Folder Monitoring Program Using clamdscan on macOS

This memorandum describes how to create a small folder monitoring program using clamdscan.
The program consists of the following six components:

  1) fswatch: A file change monitor
  2) ClamavSentry: Shell Script
  3) SentryAlert.scpt: AppleScript
      3-1) When using the "display notification" command...
      3-2) When using the "display dialog" command...
  4) org.clamav.sentry.plist: LaunchAgents plist
  5) xbar: An application that puts the output in the menu bar
  6) ClamavSentry.10m.sh: xbar plugin

For instructions on how to build ClamAV, please refer to "How to build ClamAV® using the CMake Build System on macOS".

And Links…




1) fswatch: A file change monitor

fswatch is a file change monitor that receives notifications when the contents of the specified files or directories are modified.

1. Download the latest fswatch
cd ~
curl -LO https://github.com/emcrisostomo/fswatch/releases/download/1.21.0/fswatch-1.21.0.tar.gz
tar xzf fswatch-1.21.0.tar.gz

2. Configure fswatch
cd fswatch-1.21.0
./configure --host=aarch64-apple-darwin`uname -r` --prefix=/usr/local/fswatch

3. Compile and make check
make && make check

    "make check" will end up with as below:
============================================================================
Testsuite summary for fswatch 1.21.0
============================================================================
# TOTAL: 10
# PASS:  10
# SKIP:  0
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================

4. Install fswatch
sudo make install

5. Set search path
export PATH="/usr/local/fswatch/bin:$PATH"

6. Verify fswatch installed properly
which fswatch
/usr/local/fswatch/bin/fswatch

fswatch --version
fswatch 1.21.0
Copyright (C) 2013-2025 Enrico M. Crisostomo.
License GPLv3+: GNU GPL version 3 or later.




2) Create and Place ClamavSentry

ClamavSentry is a Shell Script that performs the following actions:
  ・Monitors the specified folders using fswatch that is a file change monitor.
  ・Notifies clamdscan whenever new files are created.
  ・If clamdscan detects any viruses, it will notify SentryAlert.scpt and sound an alert.

1. Create ClamavSentry
#!/usr/bin/env bash
#
# Description: Monitors the specified folder and passes detected changes to clamdscan.
#              If a virus is detected, it notifies SentryAlert.scpt and sounds an alert.
# Name       : ClamavSentry
#

# Path to fswatch
FSWATCH="/usr/local/fswatch/bin/fswatch"

# Path to clamdscan
CLAMDSCAN="/usr/local/clamXav/bin/clamdscan"

# Path to SentryAlert.scpt
APPLE_SCRIPT="$HOME/Library/ClamAV/ClamdScan/SentryAlert.scpt"

# Path to log file
LOG_FILE="$HOME/Library/Logs/ClamdScan.log"

# Path to audio file
AUDIO_FILE="$HOME/Library/ClamAV/ClamdScan/alert.aiff"

# Path to Watch directory
WATCH_DIRS=(
  "/Volumes/Data/Downloads/"
  "$HOME/Library/Mail/"
  "$HOME/Library/Mail Downloads/"
)

"$FSWATCH" --event IsFile Created -0 -r "${WATCH_DIRS[@]}" | while IFS= read -r -d '' changed_path; do
  scan_output="$("$CLAMDSCAN" --stdout --infected --no-summary -- "$changed_path" 2>&1 || true)"
  found_lines="$(printf '%s\n' "$scan_output" | grep 'FOUND' || true)"

  if [ -n "$found_lines" ]; then
    /usr/bin/osascript "$APPLE_SCRIPT" "$found_lines" "$LOG_FILE" & /usr/bin/afplay "$AUDIO_FILE"
  fi
done

2. Grant execute permission to ClamavSentry
chmod +x ClamavSentry

3. Place ClamavSentry in /Users/xxx/Library/ClamAV/ ,for example.
/Users/xxx/Library/ClamAV/ClamavSentry




3) Create and Place SentryAlert.scpt

SentryAlert.scpt is an AppleScript that displays "Notification Alert" or "Dialog Alert" and logs the event.

  3-1) When using the "display notification" command...

  1. Create SentryAlert.scpt
on run argv
	if (count of argv) < 2 then return
	
	set foundText to item 1 of argv
	set logFilePath to item 2 of argv
	
	set msg to "Infection Found:" & linefeed & foundText
	display notification msg with title "ClamAV Alert !"
	
	set ts to do shell script "date '+%Y-%m-%d %H:%M:%S'"
	set logBlock to "-------------------------------------- SCAN LOG --------------------------------------" & linefeed & ts & linefeed & msg & linefeed & "--------------------------------------------------------------------------------------" & linefeed & linefeed
	
	do shell script "printf %s " & quoted form of logBlock & " >> " & quoted form of logFilePath
end run

  2. Grant execute permission to SentryAlert.scpt
chmod +x SentryAlert.scpt

  3. Place SentryAlert.scpt in /Users/xxx/Library/ClamAV/ClamdScan/ ,for example.
/Users/xxx/Library/ClamAV/ClamdScan/SentryAlert.scpt


  4. The following "Notification Aleart" will appear with a warning sound and you will get "ClamdScan.log" as below.


"Notification Aleart" and "ClamdScan.log"
Screenshot



  3-2) When using the "display dialog" command...

  1. Create SentryAlert.scpt using "display dialog"
on run argv
	if (count of argv) < 2 then return
	
	set foundText to item 1 of argv
	set logFilePath to item 2 of argv
	
	set msg to "Infection Found:" & linefeed & foundText
	set iconPath to POSIX file "/Users/xxx/Library/ClamAV/ClamdScan/alert.png"
		
	display dialog msg with title "                                            ClamAV Alert !" with icon file iconPath buttons "OK" default button "OK"
	
	set ts to do shell script "date '+%Y-%m-%d %H:%M:%S'"
	set logBlock to "-------------------------------------- SCAN LOG --------------------------------------" & linefeed & ts & linefeed & msg & linefeed & "--------------------------------------------------------------------------------------" & linefeed & linefeed
	
	do shell script "printf %s " & quoted form of logBlock & " >> " & quoted form of logFilePath
	
	set savedDelimiters to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "/"
	set parts to text items of foundText
	
	set folderParts to items 1 thru -2 of parts
	set AppleScript's text item delimiters to "/"
	set folderPath to folderParts as text
	set folderPath to folderPath & "/"
	
	set AppleScript's text item delimiters to savedDelimiters
	
	tell application "Finder"
		open folderPath as POSIX file
		activate
	end tell
end run

  2. Grant execute permission to SentryAlert.scpt
chmod +x SentryAlert.scpt

  3. Place SentryAlert.scpt in /Users/xxx/Library/ClamAV/ClamdScan/ ,for example.
/Users/xxx/Library/ClamAV/ClamdScan/SentryAlert.scpt


  4. The following "Dialog" will appear with a warning sound and you will get "ClamdScan.log" as below.
      Clicking the "OK" button will open a Finder window displaying the directory containing the infected files.


"Dialog" and "ClamdScan.log"
Screenshot





4) Create and Place org.clamav.sentry.plist

org.clamav.sentry.plist is a plist file for LaunchAgents that starts ClamavSentry using launchctl at login.


1. Create org.clamav.sentry.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>org.clamav.sentry</string>
	<key>Disabled</key>
	<false/>
	<key>KeepAlive</key>
	<dict>
		<key>PathState</key> 
		<dict>
		<key>/private/tmp/clamd.socket</key>
		<true/> 
		</dict>
	</dict>
	<key>ProgramArguments</key>
	<array>
		<string>/Users/xxx/Library/ClamAV/ClamavSentry</string>
	</array>
</dict>
</plist>

2. Place SentryAlert.scpt in /Users/xxx/Library/LaunchAgents/.
/Users/xxx/Library/LaunchAgents/org.clamav.sentry.plist




5) Install xbar

xbar is an application that puts the output in the menu bar.

1. Download the latest xbar
cd ~
curl -LO https://github.com/matryer/xbar/releases/download/v2.1.7-beta/xbar.v2.1.7-beta.zip
unzip xbar.v2.1.7-beta.zip

2. Place xbar.app in /Applications/Utilities/ ,for example.
mv xbar.app /Applications/Utilities/




6) Create and Place ClamavSentry.10m.sh

ClamavSentry.10m.sh is a xbar plugin that displays the processes of ClamavSentry in the menu bar using xbar.

1. Create ClamavSentry.10m.sh

#!/usr/bin/env bash
#
# Description: Monitor the processes of ClamavSentry and display them in the menu bar.
# Name       : ClamavSentry.10m.sh
#
# Refresh time: 10 minutes
#               {ClamavSentry}.{10m}.{sh}
#

PROCESS_NAME=$HOME/Library/ClamAV/ClamavSentry
FONT_SIZE=18
FONT_COLOR_DEAD=#fe0000
FONT_COLOR_ALIVE=#e4e4e4

count=`ps -ef | grep $PROCESS_NAME | grep -v grep | wc -l`
    if [ $count = 0 ]; then
        # If the process is not running
        echo "χ| size=$FONT_SIZE color=$FONT_COLOR_DEAD"
    else
        # If the process is running
        echo "ρ| size=$FONT_SIZE color=$FONT_COLOR_ALIVE"
    fi

2. Place ClamavSentry.10m.sh in /Library/Application Support/xbar/plugins/.
/Library/Application Support/xbar/plugins/ClamavSentry.10m.sh





"Menu bar Icons that shows the processes of ClamavSentry"

Screenshot
Links…

mail