Look for file changes and kick off actions with Watchman

On Guard

Excluding Files

When you define a trigger, you can specify files to exclude; that is, you can prevent the trigger from executing if a file name contains a particular pattern. Note that with rsync, such an exclusion will not be taken in account. The following command can be performed at run time, and the configuration will be updated accordingly:

watchman -- trigger /opt/repos 'repos-sync' \
             -X '*.css' \
             -I '*' -- /usr/local/sbin/sync.sh

The -X excludes a pattern and -I includes a pattern. For a full accounting of pattern syntax, please refer to the Watchman website [4].

When a new file or any change inside the watched directory is detected, Watchman waits for the filesystem (the directory) to be idle for a time before dispatching triggers. By default, this time is 20 milliseconds, and this option is named "settle". To increase the amount of time, you must set the "settle" option in the global configuration file – /etc/watchman.json by default. This file uses JSON syntax, as well:

{
   "settle": 60
}

The settle option is useful if you want to prevent the script from executing before a large file write has completed.

Real-Time Virus Scanner

Watching a real-time virus scanner, such as the free antivirus ClamAV [5] or the free anti-malware tool Linux Malware Detect (a.k.a., maldet) [6], would be another interesting use case for Watchman. The maldet tool uses the Linux inotify facility to perform real-time scanning; however, Solaris/Illumos do not have inotify, so you would be unable to use this functionality on such operating systems. In this case, a good solution would be to use Watchman.

For example, suppose you want to scan files for viruses with the clamscan utility. Whenever a file is added, changed, or deleted, the Watchman service will trigger the scanner.sh script (Listing 4), which invokes the virus scanner, passing in the file name to the $@ variable.

Listing 4

scanner.sh

01 #!/bin/bash
02
03 for file in $@
04 do
05   clamscan --stdout --no-summary --infected ${WATCHMAN_ROOT}/$file
06   EL=$?
07   if [ $EL -eq 1 ]
08   then
09     # Virus found
10     echo "Virus found: ${WATCHMAN_ROOT}/$file" | \
         mailx -s "Virus found" mail@example.com
11   elif [ $EL -eq 2 ]
12   then
13     # Clamscan error
14     echo "Scan error: ${WATCHMAN_ROOT}/$file" | \
         mailx -s "Scan error" mail@example.com
15   fi
16   # Else no virus found
17 done

However, when you delete a file, Watchman still kicks the trigger, and the name of the deleted file is passed to your script, even though you don't need to scan a non-existent file; therefore, you need to use extended trigger syntax (Listing 5). The key options are "exists" and "append_files": true. The append_files entry enables the arguments – that is, the list of new or changed files – to be passed to the script, and "exists" tells Watchman to trigger the action only if the file exists.

Now, if you execute

watchman watch /opt/share

Watchman passes a list of changed, but not deleted, files to the script, using the relative path to "root" (/opt/share). Of course, you could also use clamdscan, if the clamd service is up and running, or the aforementioned maldet tool on Linux.

Listing 5

Extended Trigger Syntax

01 watchman -j <<-EOT
02 ["trigger", "/opt/share", {
03   "name": "scanner",
04   "expression": ["allof", ["match", "*"], ["exists"]],
05   "command": ["/usr/local/sbin/scanner.sh"],
06   "append_files": true
07 }]
08 EOT

Shutdown and Reboot

The correct way to shut down Watchman is:

watchman shutdown-server

Remember that if you reboot your server, you need a way to start Watchman automatically at bootup. For SmartOS [7], you can import a sample SMF manifest from the watchman-pkgsrc GitHub site [8] (check the paths). For CentOS 7 with the systemd suite, you can create the file /etc/systemd/system/watchman.service containing something like Listing 6. Finally, you need to issue

systemctl enable watchman
systemctl start watchman

to enable Watchman on bootup and start the service.

Listing 6

watchman.service

01 [Unit]
02 Description=Watchman
03 After=network.target
04
05 [Service]
06 Type=simple
07 User=root
08 ExecStart=/usr/local/bin/watchman --log-level 1 watch-list -f
09 ExecStop=/usr/local/bin/watchman shutdown-server
10
11 [Install]
12 WantedBy=multi-user.target

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus