Wednesday, August 1, 2012

Fail2Ban with Pushover Notification

I recently purchased the pushover notification app for android due to a discount offer. As a result, I decide to integrate pushover notification with some Fedora services on my home server.

Fail2Ban

To enable pushover notification, I added a pushover-notify action to /etc/fail2ban/action.d/pushover-notify.conf.
# Fail2Ban configuration file
#

[Definition]
# Notify on Startup
actionstart = /usr/bin/curl -s -F "token="  -F "user=" -F "title=[Fail2Ban]" -F "message=Jail  has been started successfully." https://api.pushover.net/1/messages
# Notify on Shutdown
actionstop = /usr/bin/curl -s -F "token="  -F "user=" -F "title=[Fail2Ban]" -F "message=Jail  has been stopped." https://api.pushover.net/1/messages
# 
actioncheck = 
# Notify on Banned
actionban = /usr/bin/curl -s -F "token="  -F "user=" -F "title=[Fail2Ban]  banned" -F "message=Banned IP:  Attempts:  `geoiplookup `" https://api.pushover.net/1/messages
# Notify on Unbanned
actionunban = 

[Init]
# Defaut name of the chain
#
name = default

# Application token key
#
token = PLACE_YOUR_APPLICATION_TOKEN_HERE

# User API key
#
user = PLACE_YOUR_USER_API_KEY_HERE

This action script uses curl and geoiplookup. Since I have SELinux enforced, I had to add policies to allow this action to run. Once done, I edit my jail.conf to enable this action.

Smartd

Add the curl command to the /usr/libexec/smartmontools/smartdnotify.

Apcaccess

Finally, I added pushover notification to my UPS monitoring services to notify me for power blackout.

Sunday, June 3, 2012

Grabbing continuous stream from IP cam

I own two Linksys WVC54GCA IP cameras. Recently, I had a need to capture a continuous stream instead of the motion activated mode where I ended up with hundreds of mp4 on my ftp server. So after looking around I found out that you can capture http stream using mplayer. So I wrote a bash script to do it.
 #!/bin/bash
#
# Duck-Wrath
# 31st May 2012
#

CHK_INT=20      # in seconds
VID_LEN=3600    # in seconds
LOGFILE=linksys_capture.log

if [ -z "$username" ]; then
   read -p "Enter Username: " username
fi

if [ -z "$password" ]; then
   read -s -p "Enter Password: " password
   printf "\n"
fi

if [ -z "$CAM_IP" ]; then
   read -p "Enter Camera IP: " CAM_IP
fi

# Linksys http URL for asf (MJPEG)
#CAM_URL=http://${CAM_IP}/img/video.mjpeg
# Linksys http URL for asf (MPEG4)
CAM_URL=http://${CAM_IP}/img/video.asf

echo "Grabbing video from ${CAM_URL}..." >> ${LOGFILE}

while [ 1 ]; do
    ASFFILE=`date +%Y%m%d-%H%M%S`.asf
    start=`date +%s`
    timer=0
    echo "Starting mplayer to grab stream." >> ${LOGFILE}
    mplayer -quiet -cache 32768 -dumpstream -dumpfile "${ASFFILE}" \
        -demuxer lavf "${CAM_URL}" \
        -user "${username}" -passwd "${password}" &
    MPID=$!
    echo "  Mplayer running on pid $MPID." >> ${LOGFILE}
    echo "  Saving to ${ASFFILE}" >> ${LOGFILE}
    while [ $timer -lt $VID_LEN ]; do
        if kill -0 $MPID; then
            now=`date +%s`
            sleep ${CHK_INT};
            timer=`echo "$now - $start" | bc`
        else
            echo "  *** Stream died prematurely." >> ${LOGFILE}
            echo "  *** Timer=${timer}." >> ${LOGFILE}
            timer=$VID_LEN
        fi
    done
    if kill -0 $MPID; then
        echo "  Terminating mplayer." >> ${LOGFILE}
        kill $MPID
    fi
    MP4FILE=`basename "${ASFFILE}" .asf`.mp4
    echo "Converting video to seekable ${MP4FILE}." >> ${LOGFILE}
    ffmpeg -i "${ASFFILE}" -f mp4 -vcodec copy -acodec copy "${MP4FILE}" && \
        /bin/rm "${ASFFILE}" && \
        echo "Captured file ${MP4FILE} Done." >> ${LOGFILE} &
    # start next capture
done
This scripts will prompt for username and password for the camera along with the IP. It then starts up mplayer to grab the stream and put in into background. The script then monitors the mplayer and updates a counter. Every hour (3600 seconds) it stop the stream captures and repackage the asf video into mp4. It then restarts capturing the next hour stream segment. If you remove the debugging log file generation, the script is relatively short.

Wednesday, March 28, 2012

Disabling edge-tiling in gnome-shell

After upgrading from Fedora 14 to Fedora 16, I had to spent a bit of my setting up time battling with gnome-shell. One of the more annoying features is the "snap" maximizing or "border" maximizing or (as gnome calls it) "edge-tiling". Default state of this feature is "true" as seen from the output of this command:
gconftool-2 --get /desktop/gnome/shell/windows/edge_tiling
To change it simply type:
gconftool-2 --type=boolean --set /desktop/gnome/shell/windows/edge_tiling false
Then press, Alt-F2 and type "r" to restart gnome-shell.

Unfortunately, the battle with gnome-shell isn't over.

UPDATE: ...And so the struggle continues. More stupid default behaviour in gnome-shell -- dialog boxes are locked to the titlebar. This is especially annoying when you have a large dialog box and need to enter data that is shown under it and can't move the damn dialog box. Luckily it can be changed by this command:
gconftool-2 --type=boolean --set /desktop/gnome/shell/windows/attach_modal_dialogs false

Wednesday, February 29, 2012

How to recursively traverse boost property tree

Currently, I find the documentation for boost::property_tree to be terrible. Hence, I hope this example will help others to work out how to use BOOST_FOREACH and recursion to traverse down the boost property tree. Here's how to create a class that loads and XML file to a property_tree, then display the hierarchy and then saves to another XML file.

 #include <iostream>  
 #include <string>  
 #include <fstream>  
 #include <boost/foreach.hpp>  
 #include <boost/property_tree/ptree.hpp>  
 #include <boost/property_tree/xml_parser.hpp>  
 #include <locale>  
   
 using boost::property_tree::ptree;  
 using namespace std;  
   
 class configuration {  
  ptree pt;  
 public:  
  // constructor  
  configuration(const string& filename) {  
   load(filename); };  
  // internal property tree function  
  ptree load(const string& filename) {  
   return import_xml(filename); };  
  void save(const string& filename) {   
   export_xml(filename,pt); };  
  // import export property tree function  
  ptree property_tree(void) {   
   return pt; };  
  void display(void) {  
   display(0, pt); };  
 private:  
  ptree import_xml(const string& filename) {  
   ifstream input(filename.c_str());  
   read_xml(input, pt);  
   return pt; };  
  void export_xml(const string& filename, const ptree& pt) {  
   boost::property_tree::xml_writer_settings<char> w(' ',2);  
   write_xml(filename, pt, locale(), w); };  
  void display(const int depth, const ptree& tree) {  
   BOOST_FOREACH( ptree::value_type const&v, tree.get_child("") ) {  
    ptree subtree = v.second;  
    string nodestr = tree.get<string>(v.first);  
      
    // print current node  
    cout << string("").assign(depth*2,' ') << "* ";  
    cout << v.first;  
    if ( nodestr.length() > 0 )   
      cout << "=\"" << tree.get<string>(v.first) << "\"";  
    cout << endl;  
      
    // recursive go down the hierarchy  
    display(depth+1,subtree);  
   }  
  };  
 };  

#define DEFAULT_CALORIES 0  
   
 int main(void)  
 {  
  configuration cfg("test_input.xml");  
  cfg.display();  
  cfg.save("test_output.xml");  
    
  // example to grab data from property tree  
  int calories = cfg.property_tree().get<int>("collection.recipe.nutrition.<xmlattr>.calories",DEFAULT_CALORIES);  
  cout << "Calories = " << calories << endl;  
   
  return 0;  
 }  

Here is a sample test_input.xml file:

 <?xml version="1.0" encoding="UTF-8"?>  
 <collection>  
  <description>  
    Some recipes used for the XML tutorial.  
  </description>  
  <recipe>  
   <title>Beef Parmesan with Garlic Angel Hair Pasta</title>  
   <ingredient name="beef cube steak" amount="1.5" unit="pound"/>  
   ...  
   <preparation>  
    <step>  
     Preheat oven to 350 degrees F (175 degrees C).  
    </step>  
    ...  
   </preparation>  
   <comment>  
    Make the meat ahead of time, and refrigerate over night, the acid in the  
    tomato sauce will tenderize the meat even more. If you do this, save the  
    mozzarella till the last minute.  
   </comment>  
   <nutrition calories="1167" fat="23" carbohydrates="45" protein="32"/>  
  </recipe>  
  ...  
  <!--another comment-->  
 </collection>  

The standard output when applied to this file gives:

 * collection="  
  ...  
  "  
  * description="  
    Some recipes used for the XML tutorial.  
  "  
  * recipe="  
   ...  
   "  
   * title="Beef Parmesan with Garlic Angel Hair Pasta"  
   * ingredient  
    * <xmlattr>  
     * name="beef cube steak"  
     * amount="1.5"  
     * unit="pound"  
   * preparation="  
    ...  
   "  
    * step="  
     Preheat oven to 350 degrees F (175 degrees C).  
    "  
   * comment="  
    Make the meat ahead of time, and refrigerate over night, the acid in the  
    tomato sauce will tenderize the meat even more. If you do this, save the  
    mozzarella till the last minute.  
   "  
   * nutrition  
    * <xmlattr>  
     * calories="1167"  
     * fat="23"  
     * carbohydrates="45"  
     * protein="32"  
  * <xmlcomment>="another comment"  
   

Notice that boost::property_tree create a separate child for XML
attributes and XML comments.

Monday, January 23, 2012

Player videos as a Gnome-screensavers

I have a collection of short interesting (to me anyway) videos that I've always wanted to play as a screen saver without audio. I use the gnome desktop in Fedora which uses gnome-screensaver. Search around on the internet I found this very useful post on Ubuntu's forum.

I have made some modifications. Firstly, to use a single mplayer line with the shuffle command to the full collection. Secondly, to kill mplayer and all of its child threads whenever gnome-screensaver exits (otherwise, you are left with many running mplayers without a window id to feed the video output to). The second part was a bit tricky to do properly since killing the parent mplayer did not kill all the child threads (probably a bug in mplayer). So here is the code:

 #! /bin/bash  
 # Movie screensaver code based on  
 # http://ubuntuforums.org/showthread.php?t=1368224  
 # modified January 2012  
 ## path to video  
 ### USER MODIFY #####  
 # Modify this to add the directories with the videos you want played.  
 VIDEO=( "/mnt/Storage1/Video_Screensavers/*" \  
     "/mnt/Storage1/Videos/RSA_Animate/*" )  
 #####################  
 if [ ! -z $XSCREENSAVER_WINDOW ]; then  
      # allow this script to run as a standalone without gnome-screensaver  
      WINDOW="-wid $XSCREENSAVER_WINDOW"  
 fi  
 ## setup MPlayer aruments, remove -nosound if you want the video  
 ## to play sound. If you have to specify the video driver to use  
 ## then add that to the list  
 MPLAYERARGS="-nosound -nolirc $WINDOW -nostop-xscreensaver -fs -really-quiet -shuffle"  
 ## we handle SIGTERM and SIGINT here to kill the child  
 ## if active then quit.  
 function ex {  
   pkill -TERM -P $CPID mplayer  
   kill -s 9 $CPID  
   exit 0  
 }  
 trap ex SIGINT SIGTERM  
 mplayer $MPLAYERARGS -loop 0 ${VIDEO[*]} < /dev/null &  
 CPID=$!  
 wait $CPID  

Copy this script (called movie.sh) to /usr/libexec/xscreensaver/ (in Fedora). Add xscreensaver-movie.desktop to /usr/share/applications/screensavers/.

 [Desktop Entry]  
 Encoding=UTF-8  
 Name=Movie  
 Comment=Plays Videos  
 TryExec=/usr/libexec/xscreensaver/movie.sh  
 Exec=/usr/libexec/xscreensaver/movie.sh  
 StartupNotify=false  
 Terminal=false  
 Type=Application  
 Categories=GNOME;Screensaver;  
 OnlyShowIn=GNOME;  

Now my process list is free of rogue mplayer processes.