Sunday, February 17, 2013

Fail2ban-client ImportError

Fedora has proposed compacting the linux filesystem hierarchy by moving some of the top level directories to usr. I am currently in the process of upgrading my home server from Fedora 16 to 18. Recently, I encountered a problem with fail2ban-client. I get the following error
# fail2ban-client -h
Traceback (most recent call last):
  File "/bin/fail2ban-client", line 35, in 
    from common.version import version
ImportError: No module named common.version
also described here with full patch given here. Once this patch was manually applied it worked perfect. However, the changes were reseted when the next fail2ban update. Until Fedora fixes this problem, a better temporary workaround is to add the python path to sys.path by adding it to PYTHONPATH environment. Create the following file /etc/profile.d/fail2ban.sh containing:
if [ -z "${PYTHONPATH}" ]; then
   PYTHONPATH="/usr/share/fail2ban"
else
   PYTHONPATH="/usr/share/fail2ban:${PYTHONPATH}"
fi
export PYTHONPATH
Alternatively, swap the the order of /bin and /usr/bin in PATH by editing /etc/profile.

Sunday, February 3, 2013

Creating Steam Client Installer RPM for Fedora 16, 17 and 18

As you might guess, I'm a long-time Linux user at work and at home. I have a Windows partition on my laptop that I only boot to when I want to play games. I'm also a Steam user. So when I heard that Steam was coming to Linux, I was over the moon. However, I'm a veteran Fedora user since Fedora Core 3. My laptop is currently running Fedora 16 (x86_64) and I play around with different Linux distribution using VirtualBox.

So recently, I decided to port Steam's deb package to Fedora's RPM. After unpacking the debian file and looking the dependencies, I decide to build my RPM for Fedora 17 (x86_64) (from KDE spin ISO) on a VirtualBox as the dependencies required some newer versions of packages that weren't available on Fedora 16. Here is the SPEC file that I create for fedora 17 based on debian's package control file.

Here are the following steps to creating a Fedora steam rpm and installing it (tested on a virtualbox machine installed with x86_64 Fedora 16 and Fedora 17). It should work for Fedora 18, but have yet to test it.
  1. Install rpmbuild environment according to this guide:
    # sudo yum install @development-tools
    # sudo yum install fedora-packager
    # rpmdev-setuptree
  2. Download the latest steam debian package from steam's repo site:
    # mkdir steam
    # cd steam
    # wget -c "http://repo.steampowered.com/steam/archive/precise/steam_1.0.0.22_i386.deb"
  3. Unpack the debian file and the package tarball:
    # ar xv steam_1.0.0.22_i386.deb
  4. Patch and repack the tarball with the dirctory structure expected by rpmbuild:
    # mkdir steam-1.0.0.22
    # tar zxvf data.tar.gz -C steam-1.0.0.22
    # rm -rf steam-1.0.0.22/etc
    # mv -iv steam-1.0.0.22/usr/bin/steamdeps steam-1.0.0.22/usr/bin/steamdeps.orig
    # ln -s /bin/cat steam-1.0.0.22/usr/bin/steamdeps
    # tar zcvf steam-1.0.0.22.tar.gz steam-1.0.0.22
    # mv -iv steam-1.0.0.22.tar.gz ~/rpmbuild/SOURCES
  5. Create the SPEC steam-1.0.0.22-1.x86_64.fc17.spec file based on debian control specification inside control.tar.gz:
     # Don't try fancy stuff like debuginfo, which is useless on binary-only  
     # packages. Don't strip binary too  
     # Be sure buildpolicy set to do nothing  
     %define    __spec_install_post %{nil}  
     %define     debug_package %{nil}  
     %define    __os_install_post %{_dbpath}/brp-compress  
     Name: steam  
     Version: 1.0.0.22 
     Release: 1.fc17  
     Summary: Steam open beta client  
     Group: Applications/Games  
     SOURCE0: %{name}-%{version}.tar.gz  
     URL: http://store.steampowered.com/  
     Vendor: Valve Corporation <linux@steampowered.com>  
     License: Steam  
     BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root  
     Requires: libcurl%{?_isa} >= 7.16.2, mesa-dri-drivers%{?_isa}, mesa-libGL%{?_isa}, libjpeg-turbo%{?_isa}, libogg%{?_isa} >= 1.0rc3, pixman%{?_isa} >= 0.24.4, SDL%{?_isa} >= 1.2.10-1, libtheora%{?_isa} >= 1.0, libudev%{?_isa} >= 175, libvorbis%{?_isa} >= 1.1.2, zenity >= 3.4.0, alsa-lib%{?_isa} >= 1.0.23, glibc%{?_isa} >= 2.15, cairo%{?_isa} >= 1.6.0, cups >= 1.4.0, dbus >= 1.2.14, fontconfig >= 2.8.0, freetype >= 2.3.9, gcc >= 4.1.1, libgcrypt%{?_isa} >= 1.4.5, gdk-pixbuf2%{?_isa} >= 2.22.0, glib2%{?_isa} >= 2.14.0, gtk2%{?_isa} >= 2.24.0, nspr%{?_isa}, nss%{?_isa} >= 3.12.3, openal-soft%{?_isa} >= 1.13, pango%{?_isa} >= 1.22.0, libpng-compat%{?_isa} >= 1.2.13, pulseaudio >= 0.99.1, pulseaudio-libs%{?_isa} >= 0.99.1, libstdc++%{?_isa} >= 4.6, libX11%{?_isa} >= 1.4.99.1, libXext%{?_isa}, libXfixes%{?_isa}, libXi%{?_isa} >= 1.2.99.4, libXinerama%{?_isa}, libXrandr%{?_isa} >= 1.2.99.3, libXrender%{?_isa}, zlib%{?_isa} >= 1.2.3.3  
     %description  
      cut and paste steam's license here or write your own description.
    
     %prep  
     %setup -q  
     %build  
     # Empty section  
     %install  
     rm -rf %{buildroot}  
     mkdir -p %{buildroot}  
     # in builddir  
     cp -a * %{buildroot}  
     %post  
     %postun  
     %clean  
     rm -rf %{buildroot}  
     %changelog  
     %files  
     %defattr(-,root,root,-)  
     %{_bindir}/*  
     %{_libdir}/*  
     %{_datadir}/*  
    
    Remember to edit the version number to match the tarball version number (i.e. Edit line label "Version:" and "Release:"). Copy the spec file into the ~/rpmbuild/SPECS directory. (Fedora 16) Since fc16 is quite old, the packages version numbers need to be shifted back. Replace the "Requires: ..." line with the following.
     Requires: libcurl%{?_isa} >= 7.16.2, mesa-dri-drivers%{?_isa}, mesa-libGL%{?_isa}, libjpeg-turbo%{?_isa}, libogg%{?_isa} >= 1.0rc3, pixman%{?_isa} >= 0.24.4, SDL%{?_isa} >= 1.2.10-1, libtheora%{?_isa} >= 1.0, libudev%{?_isa} >= 173, libvorbis%{?_isa} >= 1.1.2, zenity >= 3.2.0, alsa-lib%{?_isa} >= 1.0.23, glibc%{?_isa} >= 2.14, cairo%{?_isa} >= 1.6.0, cups >= 1.4.0, dbus >= 1.2.14, fontconfig >= 2.8.0, freetype >= 2.3.9, gcc >= 4.1.1, libgcrypt%{?_isa} >= 1.4.5, gdk-pixbuf2%{?_isa} >= 2.22.0, glib2%{?_isa} >= 2.14.0, gtk2%{?_isa} >= 2.24.0, nspr%{?_isa}, nss%{?_isa} >= 3.12.3, openal-soft%{?_isa} >= 1.12, pango%{?_isa} >= 1.22.0, libpng%{?_isa} >= 1.2.13, pulseaudio >= 0.9.23, pulseaudio-libs%{?_isa} >= 0.9.23, libstdc++%{?_isa} >= 4.6, libX11%{?_isa} >= 1.4.3, libXext%{?_isa}, libXfixes%{?_isa}, libXi%{?_isa} >= 1.2.99.4, libXinerama%{?_isa}, libXrandr%{?_isa} >= 1.2.99.3, libXrender%{?_isa}, zlib%{?_isa} >= 1.2.3.3, libgpg-error%{?_isa} >= 1.10, PackageKit-gtk-module%{?_isa}, libcanberra-gtk2%{?_isa}, libtxc_dxtn%{?_isa}, gtk2-engines%{?_isa}, xorg-x11-drv-nvidia-libs%{?_isa}   
    
    Note: the last package xorg-x11-drv-nvidia-libs is specific to my laptop which has a nvidia graphics card. Remove or modify this if this does not match your system.
  6. Build the rpm package.
    # cd ~/rpmbuild
    # rpmbuild --target  i686 -bb SPECS/steam-1.0.0.22-1.fc17.i686.spec
    The rpm should have been created in RPMS/i686 directory.
  7. (Fedora 16) Back port libX11 from F17 or F18.
    # wget -c "http://dl.fedoraproject.org/pub/fedora/linux/releases/17/Fedora/source/SRPMS/l/libX11-1.4.99.901-2.fc17.src.rpm"
    # rpm -ihv libX11-1.4.99.901-2.fc17.src.rpm
    # sudo yum install libXau-devel libXdmcp-devel libxcb-devel xorg-x11-proto-devel xorg-x11-util-macros xorg-11-xtrans-devel
    # sudo yum install libXau-devel.i686 libXdmcp-devel.i686 libxcb-devel.i686
    # sudo yum install glibc.i686 glibc-devel.i686 libgcc.i686 libstdc++.i686
    # rpmbuild --target i686 -ba SPECS/libX11.spec
    # rpmbuild -ba SPECS/libX11.spec # make for x86_64
    # sudo yum localinstall RPMS/i686/libX11-1.4.99.901-2.fc17.i686.rpm RPMS/i686/libX11-devel-1.4.99.901-2.fc17.i686.rpm RPMS/x86_64/libX11-1.4.99.901-2.fc17.x86_64.rpm RPMS/x86_64/libX11-devel-1.4.99.901-2.fc17.x86_64.rpm RPMS/noarch/libX11-common-1.4.99.901-2.fc17.noarch.rpm
  8. Everything so far has been using Fedora's repository. However, the steam client requires s3tc texture compression algorithm libraries which isn't available on Fedora's repo. You will need to add a third party repo such as rpmfusion:
    # su -c "yum localinstall --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-17.noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-17.noarch.rpm"
    # sudo yum install libtxc_dxtn libtxc_dxtn.i686
    Adjust the first URL to match the fedora version number (FC17 is assumed in this example).
  9. And finally, install steam rpm (and libX11 if using Fedora 16).
    sudo yum localinstall RPMS/i686/steam-1.0.0.22-1.fc17.i686.rpm RPMS/i686/libX11-1.4.99.901-2.fc17.i686.rpm
  10. If you have been blessed, steam should be installed at this point. You can start up steam by typing:
    steam
    If you are behind a firewall, the steam client respects proxy environment variables: http_proxy, https_proxy, and all_proxy. The steam binary installed by rpm is really just a client downloader. You'll need to be connected to internet for the really client binary to be downloaded and installed.

Good gaming.

Remark: The code for steamdeps is probably a bad way to test dependencies as it is very debian-specific. A more distro agnostic way is required.

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.