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!)

Compile ClamAV from source on Mac OS X

The following instructions for compiling & installing the ClamAV virus scanner on Mac OS X require an admin user account and Xcode. Works despite some compiler warnings. Use at your own risk!

1. disable an already installed ClamAV system

clamconf      # get your ClamAV configuration
clamconf -n
clamconf | grep DatabaseOwner


# the following applies to the already installed ClamAV system of user clamavadmin at /private/var/clamavadmin
# cf. Run ClamAV from a system service agent account, http://textsnippets.com/posts/show/1406
# cf. Automated virus scanning with ClamAV on Mac OS X 10.4, http://textsnippets.com/posts/show/1357


# view clamd.log in another Terminal window
open /bin/bash
sudo tail -n 50 -f /private/var/clamavadmin/log/clamd.log

# SHUTDOWN clamd 
# cf. man clamd
(sleep 3; echo PING; sleep 3; echo exit) | telnet -u /private/var/clamavadmin/tmp/clamd
(sleep 3; echo SHUTDOWN; sleep 3; echo exit) | telnet -u /private/var/clamavadmin/tmp/clamd

# alternative: sudo /opt/local/bin/port install socat
echo PING | /opt/local/bin/socat - /private/var/clamavadmin/tmp/clamd     
echo SHUTDOWN | /opt/local/bin/socat - /private/var/clamavadmin/tmp/clamd  

# alternative
function clamd_local_socket() {

   local_socket="$(/usr/local/bin/clamconf -n | awk -F '"' '/LocalSocket/ {print $2}')"

   if [[ -z "$local_socket" ]] || [[ ! -S "$local_socket" ]]; then    # cf. help test
      printf "No such local unix socket: $local_socket \n"
      return 1
   fi

   #printf -- "$@\x00$local_socket" | /usr/bin/sudo ruby -rsocket -n -e '
   printf -- "$@\x00$local_socket" | ruby -rsocket -n -e '
      args = $_.split(/\000/, 2)
      unix_socket = UNIXSocket::open(args.last)
      unix_socket.send(args.first, 0)
      print unix_socket.recvfrom(1000).first
      unix_socket.close
   '

return 0
}

clamd_local_socket PING
clamd_local_socket SHUTDOWN


function clamavadmin_perms() {

   if [[ -d "/private/var/clamavadmin" ]]; then
      printf '\nSetting permissions in the clamavadmin directory: /private/var/clamavadmin\n\n'
   else
      printf '\nNo clamavadmin directory at: /private/var/clamavadmin\n\n'
      return 1
   fi

   declare sudo=/usr/bin/sudo

   $sudo /bin/mkdir -p /private/var/clamavadmin/log
   $sudo /bin/mkdir -p /private/var/clamavadmin/tmp
   $sudo /bin/mkdir -p /private/var/clamavadmin/share/clamav   # ClamAV database directory
   $sudo /usr/bin/touch /private/var/clamavadmin/log/clamd.log 
   $sudo /usr/bin/touch /private/var/clamavadmin/log/freshclam.log

   $sudo /usr/sbin/chown -R clamavadmin:clamavadmin /private/var/clamavadmin
   $sudo /bin/chmod -R 0750 /private/var/clamavadmin 
   #$sudo /bin/chmod -R 0770 /private/var/clamavadmin   # for debugging only
   $sudo /bin/chmod 0777 /private/var/clamavadmin/tmp/clamd 2>/dev/null  # local unix socket file
   $sudo /usr/bin/find /private/var/clamavadmin -print0 | /usr/bin/xargs -0 $sudo /bin/ls -ldG
   return 0
}


# restart clamd after SHUTDOWN (socket file removed)
#if [[ -e "/private/var/clamavadmin/tmp/clamd" ]]; then sudo /bin/rm -f "/private/var/clamavadmin/tmp/clamd" ; fi
#sudo "$(/usr/bin/which clamd)" -c /private/var/clamavadmin/clamd.conf
#clamavadmin_perms


# get running clamav launchd services
launchctl list | grep -i clam
sudo launchctl list | grep -i clam

launchctl unload -w ~/Library/LaunchAgents/net.clamav.dirwatcher.plist 2>/dev/null
sudo launchctl unload -w /Library/LaunchDaemons/net.clamav.dirwatcherd.plist 2>/dev/null
sudo launchctl unload -w /Library/LaunchDaemons/net.clamav.clamd.plist 2>/dev/null
sudo launchctl unload -w /Library/LaunchDaemons/net.clamav.update.clamd.db.plist 2>/dev/null

# check for: <key>Disabled</key><true/>
open -e ~/Library/LaunchAgents/net.clamav.dirwatcher.plist
sudo nano /Library/LaunchDaemons/net.clamav.dirwatcherd.plist
sudo nano /Library/LaunchDaemons/net.clamav.clamd.plist
sudo nano /Library/LaunchDaemons/net.clamav.update.clamd.db.plist


sudo reboot

export PATH=/usr/local/bin:/usr/local/sbin:/usr/local/lib:/usr/local/include:/usr/bin:/bin:/usr/sbin:/sbin


2. compile & install gawk on Mac OS X

# http://www.gnu.org/software/gawk/
cd ~/Desktop
curl -L -O http://ftp.gnu.org/pub/gnu/gawk/gawk-3.1.6.tar.gz
tar -xzf gawk-3.1.6.tar.gz
cd gawk-3.1.6
./configure --help
./configure --disable-nls --prefix=/usr/local
make
sudo make install
/usr/local/bin/gawk --version


3. compile & install the GNU Multiple Precision Arithmetic Library

# http://gmplib.org
# http://gmplib.org/macos.html

cd ~/Desktop
curl -L -O ftp://ftp.gnu.org/gnu/gmp/gmp-4.2.2.tar.gz   # cf. fwftp, http://textsnippets.com/posts/show/1284
tar -xzf gmp-4.2.2.tar.gz
cd gmp-4.2.2

./configure --help
./configure

make
make check
sudo make install

# test
sudo find /usr/local -iregex ".*gmp.*" -print0 | xargs -0 sudo ls -ldG
otool -Lv /usr/local/lib/libgmp.3.4.2.dylib


4. create ClamAV user & group

# to set up a ClamAV user & group run the first script from: http://textsnippets.com/posts/show/1405

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

You are going to create a system service agent account!

Enter first name: clamavadmin

Note: The last name is optional and defaults to "agent" if you just press <return>!
Enter last name: 

Note: The user shell is optional and defaults to "/usr/bin/false" if you just press <return>!
Enter user shell: /bin/bash

Note: The home directory is optional and defaults to "/private/var/empty" if you just press <return>!
Enter home directory: /private/var/clamavadmin

System service agent account:  clamavadmin  successfully created!

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


sudo mkdir -p /private/var/clamavadmin/log
sudo touch /private/var/clamavadmin/log/clamd.log 
sudo touch /private/var/clamavadmin/log/freshclam.log
sudo mkdir -p /private/var/clamavadmin/tmp

# make sure permissions are set correctly in /private/var/clamavadmin
clamavadmin_perms   # see function above


# add clamavadmin to group admin and group $(logname)
# add $(logname) to group clamavadmin
sudo dscl . -append /Groups/admin GroupMembership clamavadmin
sudo dscl . -append /Groups/$(logname) GroupMembership clamavadmin
sudo dscl . -append /Groups/clamavadmin GroupMembership $(logname)

#sudo dscl . -delete /Groups/admin GroupMembership clamavadmin 
#sudo dscl . -delete /Groups/$(logname) GroupMembership clamavadmin  
#sudo dscl . -delete /Groups/clamavadmin GroupMembership $(logname)   

# test
dscl . -list /Users  | grep -i clamav
dscl . -list /Groups  | grep -i clamav

dscl . -read  /Users/clamavadmin uid
dscl . -read  /Groups/clamavadmin gid

dscl . -search /Groups GroupMembership clamavadmin
printf -- "$(dscl . -search /Groups GroupMembership clamavadmin | awk '{print $1}' | tr '\n' ' ')\n"
id -Gn clamavadmin


5. compile & install ClamAV

# http://wiki.clamav.net/Main/InstallFromSource
# http://downloads.topicdesk.com/docs/Updating_clamav_on_OS_X_Server.pdf
# http://downloads.topicdesk.com/docs/clamav_extras.tar.gz

cd ~/Desktop
open http://freshmeat.net/projects/clamav/
curl -L -O http://freshmeat.net/redir/clamav/29355/url_tgz/clamav-0.92.1.tar.gz
tar -xzf clamav-0.92.1.tar.gz
cd clamav-0.92.1

./configure --help

# Compile bug for clamav 0.92 with latest xcode 
# http://discussions.apple.com/thread.jspa?messageID=6190171
# http://www.mail-archive.com/clamav-users@lists.clamav.net/msg28420.html

CFLAGS="-O0" ./configure \
--prefix=/usr/local --mandir=/usr/local/share/man --sysconfdir=/private/var/clamavadmin \
--with-dbdir=/private/var/clamavadmin/share/clamav --with-datadir=/private/var/clamavadmin/share/clamav \
--with-user=clamavadmin --with-group=clamavadmin \
--enable-bigstack --enable-static --disable-shared

make

sudo make install


# test
man -w    # show directories searched for man pages
man -aW clamd 2>/dev/null
man -aW clamdscan 2>/dev/null
man -aW clamscan 2>/dev/null
man -aW freshclam 2>/dev/null
man -aW clamconf 2>/dev/null


# get an overview of your ClamAV file & folder permissions in /usr/local
sudo find /usr/local -iregex ".*clam.*" -print0 | xargs -0 sudo ls -ldG
#sudo find /usr/local \( -type f -or -type d \) -iregex ".*clam.*" -print0 | xargs -0 sudo ls -ldG

# set ClamAV file & folder permissions in /usr/local
# note: you may not need: -not -name "*.png"
sudo find /usr/local -not -name "*.png" -iregex ".*clam.*" -print0 | xargs -0 sudo chown clamavadmin:clamavadmin
sudo find /usr/local -not -name "*.png" -iregex ".*clam.*" -print0 | xargs -0 sudo chmod 0750

# reset permissions in /usr/local
# note: you may not need: -not -name "*.png"
#sudo find /usr/local  -not -name "*.png" -iregex ".*clam.*" -print0 | xargs -0 sudo chown root:wheel  
#sudo find /usr/local  -not -name "*.png" -iregex ".*clam.*" -print0 | xargs -0 sudo chmod 0755



# /private/var/clamavadmin/clamd.conf

sudo cp -p /private/var/clamavadmin/clamd.conf /private/var/clamavadmin/clamd.conf.orig

sudo sh -c '
cat << EOF > /private/var/clamavadmin/clamd.conf

LogFileMaxSize 10M
LogTime yes
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

DatabaseDirectory /private/var/clamavadmin/share/clamav    # hardcoded
LogFile /private/var/clamavadmin/log/clamd.log
TemporaryDirectory /private/var/clamavadmin/tmp
LocalSocket /private/var/clamavadmin/tmp/clamd

EOF
'

sudo nano /private/var/clamavadmin/clamd.conf


# /private/var/clamavadmin/freshclam.conf

sudo cp -p /private/var/clamavadmin/freshclam.conf /private/var/clamavadmin/freshclam.conf.orig 

sudo sh -c '
cat << EOF > /private/var/clamavadmin/freshclam.conf

UpdateLogFile /private/var/clamavadmin/log/freshclam.log
LogFileMaxSize 2M
LogTime yes
LogVerbose yes
DatabaseOwner clamavadmin
Debug yes
NotifyClamd /private/var/clamavadmin/clamd.conf   # send the RELOAD command to clamd
DatabaseDirectory /private/var/clamavadmin/share/clamav    # hardcoded
DatabaseMirror database.clamav.net

#Checks 24   # number of database checks per day
#OnUpdateExecute command
#OnErrorExecute command
#OnOutdatedExecute command   # run command when freshclam reports outdated version
#ConnectTimeout 60
#ReceiveTimeout 60

EOF
'

sudo nano /private/var/clamavadmin/freshclam.conf


/usr/local/bin/clamconf
/usr/local/bin/clamconf -n


# make sure permissions are set correctly in /private/var/clamavadmin
clamavadmin_perms   # see function above


# view clamd.log in another Terminal window
open /bin/bash
sudo tail -n 50 -f /private/var/clamavadmin/log/clamd.log

# view freshclam.log in another Terminal window
open /bin/bash
sudo tail -n 50 -f /private/var/clamavadmin/log/freshclam.log


# test
sudo /usr/local/bin/freshclam -u clamavadmin   # update virus database
sudo /usr/local/bin/clamscan ~/Desktop/clamav-0.92.1/test/*
sudo /usr/local/bin/clamdscan ~/Desktop/clamav-0.92.1/test/*

# now start clamd
if [[ -e "/private/var/clamavadmin/tmp/clamd" ]]; then sudo /bin/rm -f "/private/var/clamavadmin/tmp/clamd" ; fi
sudo /usr/local/sbin/clamd -c /private/var/clamavadmin/clamd.conf

# make sure permissions are set correctly in /private/var/clamavadmin
clamavadmin_perms   # see function above


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


# set up ClamAV launchd items

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>Disabled</key>
        <true/>
        <key>GroupName</key>
        <string>clamavadmin</string>
        <key>Label</key>
        <string>net.clamav.clamd</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/local/sbin/clamd</string>
                <string>-c</string>
                <string>/private/var/clamavadmin/clamd.conf</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>UserName</key>
        <string>clamavadmin</string>
</dict>
</plist>

if [[ -e "/private/var/clamavadmin/tmp/clamd" ]]; then sudo /bin/rm -f "/private/var/clamavadmin/tmp/clamd" ; fi
sudo launchctl load -w /Library/LaunchDaemons/net.clamav.clamd.plist 2>/dev/null
#sudo launchctl unload -w /Library/LaunchDaemons/net.clamav.clamd.plist 2>/dev/null

# make sure permissions are set correctly in /private/var/clamavadmin
clamavadmin_perms   # see function above


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


sudo nano /Library/LaunchDaemons/net.clamav.update.clamd.db.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>Disabled</key>
        <true/>
        <key>GroupName</key>
        <string>clamavadmin</string>
        <key>Label</key>
        <string>net.clamav.update.clamd.db</string>
        <key>ProgramArguments</key>
        <array>
                <string>/private/var/clamavadmin/update_clamd_db.sh</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StartInterval</key>
        <integer>20000</integer>
        <key>UserName</key>
        <string>clamavadmin</string>
</dict>
</plist>

sudo launchctl load -w /Library/LaunchDaemons/net.clamav.update.clamd.db.plist 2>/dev/null
#sudo launchctl unload -w /Library/LaunchDaemons/net.clamav.update.clamd.db.plist 2>/dev/null

# make sure permissions are set correctly in /private/var/clamavadmin
clamavadmin_perms   # see function above


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


sudo nano /private/var/clamavadmin/update_clamd_db.sh

#!/bin/bash

/bin/sleep 120

exec >/dev/console 2>&1   # write stdout & stderr to console.log

/usr/bin/curl -I -L -s --max-time 15 database.clamav.net 1>/dev/null

if [[ $? -eq 0 ]]; then 

   /bin/sleep 3

   /usr/local/bin/freshclam -u clamavadmin

   /bin/sleep 3

   # cf. /private/var/clamavadmin/freshclam.conf above:
   # NotifyClamd /private/var/clamavadmin/clamd.conf   # send the RELOAD command to clamd

   #echo RELOAD | /opt/local/bin/socat - /private/var/clamavadmin/tmp/clamd
   #/bin/sleep 3
   #echo PING | /opt/local/bin/socat - /private/var/clamavadmin/tmp/clamd
   #/bin/sleep 3

   echo -e "\n$(/bin/date "+%Y-%m-%d %H:%M:%S %Z"): clamd virus database successfully updated\n"
   exit 0

else

   echo -e "\n$(/bin/date "+%Y-%m-%d %H:%M:%S %Z"): updating the clamd virus database failed; no internet connection to database.clamav.net established\n"
   exit 0   # leave launchd item /Library/LaunchDaemons/net.clamav.update.clamd.db.plist undisturbed

fi


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


# make sure permissions are set correctly in /private/var/clamavadmin
clamavadmin_perms   # see function above


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


# cf. http://textsnippets.com/posts/show/1357

sudo nano ~/Documents/ClamAV/watchdirs.sh     

# ...

find=/usr/bin/find
clamdscan=/usr/local/bin/clamdscan
clamscan=/usr/local/bin/clamscan

#clamdscan=/opt/local/bin/clamdscan
#clamscan=/opt/local/bin/clamscan

# ...


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


# cf. http://textsnippets.com/posts/show/1400
open ~/Library/Workflows/Applications/Finder/virusscan.workflow

/usr/local/bin/clamdscan --quiet "$f" 2>/dev/null
#/opt/local/bin/clamdscan --quiet "$f" 2>/dev/null


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

launchctl load -w ~/Library/LaunchAgents/net.clamav.dirwatcher.plist 2>/dev/null
#sudo launchctl load -w /Library/LaunchDaemons/net.clamav.dirwatcherd.plist 2>/dev/null
sudo launchctl load -w /Library/LaunchDaemons/net.clamav.clamd.plist 2>/dev/null
sudo launchctl load -w /Library/LaunchDaemons/net.clamav.update.clamd.db.plist 2>/dev/null


sudo reboot


open -a Console

open /bin/bash
sudo tail -n 50 -f /private/var/clamavadmin/log/clamd.log

open /bin/bash
sudo tail -n 50 -f /private/var/clamavadmin/log/freshclam.log

# make sure permissions are set correctly in /private/var/clamavadmin
clamavadmin_perms   # see function above

sudo find /private/var/clamavadmin -print0 | xargs -0 sudo ls -ldG
sudo find /usr/local -iregex ".*clam.*" -print0 | xargs -0 sudo ls -ldG

Attach a screen before chrooting into your linux from scratch minimal system

This snippet is not so much a snippet as a tip. It's goal is to make your Linux from Scratch experience easier by allowing you the freedom of being able to attach and detach to a screen session from your host computer. Of course you would go through the book and change the chroot command to suit your needs, but just bear in mind that the chroot command you will use may be different from the one I use.

By using screen, you can start a lengthy compile and then detach, go about your business and re-attach another time. I use it primarily when I have to start a compilation from one computer, then later from another machine located somewhere else. Combined with SSH, this can be real handy.

desktop ~ # screen -S clfs
desktop ~ # chroot "${CLFS}" /tools/bin/env -i \
>     HOME=/root TERM="${TERM}" PS1='\u:\w\$ ' \
>     PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
>     /tools/bin/bash --login +h
root:/#


At any time, you can hit ctrl+a+d to detach. Then if you want to re-attach just type screen -r clfs and whamo, your right back where you left off.

Thanks again to ChrisS67 for helping me with my GCC problem (or me forgetting to install findutils) ;)