<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>./code.geek.sh</title>
	<atom:link href="http://code.geek.sh/feed/" rel="self" type="application/rss+xml" />
	<link>http://code.geek.sh</link>
	<description>Just another code geek</description>
	<lastBuildDate>Sat, 14 Apr 2012 21:31:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>New WordPress Theme: codegeek</title>
		<link>http://code.geek.sh/2012/04/new-wordpress-theme-wp-codegeek/</link>
		<comments>http://code.geek.sh/2012/04/new-wordpress-theme-wp-codegeek/#comments</comments>
		<pubDate>Sat, 14 Apr 2012 21:31:50 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=458</guid>
		<description><![CDATA[As you may have noticed, I&#8217;ve replaced the old theme here on my blog with something a little cleaner and simpler. I couldn&#8217;t really find anything I liked or wanted on the net, so I threw something simple together using Twitters excellent Bootstrap library along with a little help from Bootswatch. If you&#8217;d like a copy [...]]]></description>
			<content:encoded><![CDATA[<p>As you may have noticed, I&#8217;ve replaced the old theme here on my blog with something a little cleaner and simpler. I couldn&#8217;t really find anything I liked or wanted on the net, so I threw something simple together using <a href="http://twitter.github.com/bootstrap/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/twitter.github.com/bootstrap/?referer=');">Twitters excellent Bootstrap library</a> along with a little help from <a href="http://bootswatch.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/bootswatch.com/?referer=');">Bootswatch</a>.</p>
<p>If you&#8217;d like a copy to use or adapt, you can grab it from <a href="https://github.com/gregarmer/wp-codegeek" target="_blank" onclick="pageTracker._trackPageview('/outgoing/github.com/gregarmer/wp-codegeek?referer=');">https://github.com/gregarmer/wp-codegeek</a>. Beware though, it is by no means a complete WordPress theme and only handles my specific requirements at this point.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2012/04/new-wordpress-theme-wp-codegeek/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Replacing Django&#8217;s Nasty &#8220;runserver&#8221;</title>
		<link>http://code.geek.sh/2011/12/replacing-djangos-nasty-runserver/</link>
		<comments>http://code.geek.sh/2011/12/replacing-djangos-nasty-runserver/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 16:53:41 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Unix / Linux]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Twisted]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=415</guid>
		<description><![CDATA[Have you ever tried to have more than one person view a development site using Django&#8217;s built-in development server ? Yeah, it really sucks. Apparently concurrency wasn&#8217;t high on the features list and they have stated that it never will be. DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through [...]]]></description>
			<content:encoded><![CDATA[<p>Have you ever tried to have more than one person view a development site using <a title="Django" href="http://www.djangoproject.com/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.djangoproject.com/?referer=');">Django&#8217;s</a> <a title="Django runserver" href="https://docs.djangoproject.com/en/1.3/ref/django-admin/#runserver-port-or-address-port" target="_blank" onclick="pageTracker._trackPageview('/outgoing/docs.djangoproject.com/en/1.3/ref/django-admin/_runserver-port-or-address-port?referer=');">built-in development server</a> ? Yeah, it really sucks. Apparently concurrency wasn&#8217;t high on the features list and they have stated that it never will be.</p>
<blockquote><p>DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through security audits or performance tests. (And that&#8217;s how it&#8217;s gonna stay. We&#8217;re in the business of making Web frameworks, not Web servers, so improving this server to be able to handle a production environment is outside the scope of Django.)</p></blockquote>
<p>So how do we go about using something a little nicer without losing any of the auto-reload goodness and without having to setup a full blown production environment ?</p>
<p>There are a number of alternatives, however I&#8217;ve selected <a title="Twisted Web" href="http://twistedmatrix.com/documents/current/web/howto/web-in-60/index.html" target="_blank" onclick="pageTracker._trackPageview('/outgoing/twistedmatrix.com/documents/current/web/howto/web-in-60/index.html?referer=');">Twisted Web</a> simply because I really like the <a title="Twisted" href="http://twistedmatrix.com/trac/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/twistedmatrix.com/trac/?referer=');">twisted framework</a> and due to the experience I have in using it, I am very comfortable with it. It&#8217;s a great feature-packed web server that handles concurrency (and a ton of other things) exceptionally well.</p>
<p>So how do we use it to serve our little Django project in a development friendly way ?</p>
<p>I&#8217;ve put together some code (some borrowed from other sources) and constructed a simple replacement command called &#8220;trunserver&#8221; (twisted-runserver). You can grab this code from <a title="GitHub - trunserver" href="https://github.com/gregarmer/trunserver" target="_blank" onclick="pageTracker._trackPageview('/outgoing/github.com/gregarmer/trunserver?referer=');">Github</a>. Simply install it using the standard methods, and run it with:</p>
<pre>python manage.py trunserver [IP:PORT] [--settings=foo] [--noreload]</pre>
<p>So this will start up a twisted web instance serving your Django project and just like the build-in runserver, it will automatically reload your code when it notices that your files have been modified unless &#8211;noreload has been passed.</p>
<p>There are a few things missing at this point, like IPv6 support and static file serving, however these are on the roadmap.</p>
<p>I&#8217;ll post again with some more info once it is a little more stable and an official release has been provided.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2011/12/replacing-djangos-nasty-runserver/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The impact of being behind schedule</title>
		<link>http://code.geek.sh/2011/02/the-impact-of-being-behind-schedule/</link>
		<comments>http://code.geek.sh/2011/02/the-impact-of-being-behind-schedule/#comments</comments>
		<pubDate>Fri, 11 Feb 2011 16:43:35 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Agile]]></category>
		<category><![CDATA[Random Thoughts]]></category>
		<category><![CDATA[Software Engineering]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=393</guid>
		<description><![CDATA[In managing a group of software engineers, this is something that has happened frequently in my team and has been bothering me for a while. It&#8217;s a lot easier for me to notice, as in my case, I actively write software with my team. The problem The entire team tends to perform so much better when [...]]]></description>
			<content:encoded><![CDATA[<p>In managing a group of software engineers, this is something that has happened frequently in my team and has been bothering me for a while. It&#8217;s a lot easier for me to notice, as in my case, I actively write software with my team.</p>
<p><strong>The problem</strong></p>
<p>The entire team tends to perform so much better when we&#8217;re ahead of schedule, our spirits are high, everyone is motivated, the <a title="SCRUM" href="http://en.wikipedia.org/wiki/Scrum_(development)" target="_blank" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Scrum_development?referer=');">SCRUM</a> board is bouncing around actively and everything is going great. However, as soon as the pressure starts to increase, a few milestones are missed and things start falling a little behind schedule. The entire team rapidly starts losing hope, everyone appears lethargic, demotivation kicks in and things slowly start grinding to a halt.</p>
<p><strong>So how do we stop this ?</strong></p>
<p>In trying to curb this level of demotivation and fatigue, we first need to understand why this happens. In reality, being a bit behind schedule is really not the end of the world. Estimates are provided on project milestones, but we need to realize that they are called estimates for a reason. No matter how many proven processes your software engineering team has in place and how good you have become at determining your teams velocity, there will always be parts of a project that cannot be put into a little box with a start and end date.</p>
<p>In addition to that, even though your estimates may be quite realistic, you can never accurately gauge what other problems may come along during a sprint. In our environment, we often have &#8220;urgent&#8221; requests to deal with; bugs, emergency maintenance, and other pesky time-wasters. To the management suits upstairs, these may seem inconsequential but in my experience, they have a far greater reaching impact than the suits realize.</p>
<p>All of this unexpected work contributes to pushing the team behind schedule. Most times we can catch up without impacting the projects final delivery, but there are rare times where we fall further and further behind schedule. It is these times that the team seems to get stuck in this cycle of despair and their relative output is reduced to who shouts at them the loudest.</p>
<p>So far, I have not found a good way to reverse this mindset after it has happened. The best way to work around this problem, in my humble opinion, is to not get there in the first place. Software engineers, sales teams and clients must realize that deadlines are going to be missed, specs are not always accurate and all kinds of impediments are going to get in the way of delivering quality work on time. The best thing we can do to prevent this is to manage everyones expectations in the best way possible.</p>
<p><strong>Keeping everyone happy</strong></p>
<p>Communication is key in managing the expectations of everyone involved. It is a lot easier to keep everyone happy when they know upfront that the team is falling behind schedule. The pressure from clients is reduced when they are informed early that an expected date of delivery is unlikely to be hit, which in turn reduces the amount of pressure. This contributes greatly to keeping the workforce in high spirits, amidst the whooshing sound of missed milestones flying by, and lets them stay motivated and productive.</p>
<p>Increasing the amount of pressure really does nothing to help a project along, although this is often the only solution that the clients and non-developers can think up. In fact, I strongly believe it does just the opposite of what it was intended to do. Adding pressure to an already drowning team only culls whatever motivation there was still remaining. This leads to developers lying about the status of a project in a desperate attempt to alleviate that pressure. That inaccurate status gets communicated back to the stake holders and the cycle just begins over &#8211; except with more pressure as the team is now even further behind.</p>
<p><strong>In conclusion</strong></p>
<p>Software engineers, be honest and accurate about your actual status, it may not seem like it, but you&#8217;re only going to help yourselves in the long run. Suits, be nicer to your workforce, they&#8217;re doing the best they can. Adding more pressure is helping no-one.</p>
<p>That is all.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2011/02/the-impact-of-being-behind-schedule/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The day the routers died&#8230;</title>
		<link>http://code.geek.sh/2011/02/the-day-the-routers-died/</link>
		<comments>http://code.geek.sh/2011/02/the-day-the-routers-died/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 20:48:20 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[IPv6]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=366</guid>
		<description><![CDATA[On February 3, 1959, Buddy Holly, Richie Valens and JP Richardson (aka The Big Bopper) died in a plane crash. Don McLean immortalized that day as &#8220;The Day The Music Died&#8221; in his 1971 hit, &#8220;American Pie&#8221;. It&#8217;s somewhat ironic that on February 3, 2010 the last five /8s from the IANA IPv4 pool have [...]]]></description>
			<content:encoded><![CDATA[<p>On February 3, 1959, Buddy Holly, Richie Valens and JP Richardson (aka The Big Bopper) died in a plane crash. Don McLean immortalized that day as &#8220;The Day The Music Died&#8221; in his 1971 hit, &#8220;American Pie&#8221;.</p>
<p>It&#8217;s somewhat ironic that on February 3, 2010 the last five /8s from the IANA IPv4 pool have been distributed to the RIRs.</p>
<pre>
102/8   AfriNIC    2011-02    whois.afrinic.net ALLOCATED
103/8   APNIC      2011-02    whois.apnic.net   ALLOCATED
104/8   ARIN       2011-02    whois.arin.net    ALLOCATED
179/8   LACNIC     2011-02    whois.lacnic.net  ALLOCATED
185/8   RIPE NCC   2011-02    whois.ripe.net    ALLOCATED
</pre>
<p>During a RIPE55 meeting surrounding IPv4 exhaustion, this rephrased version of that 1971 hit was played:</p>
<p><iframe title="YouTube video player" width="480" height="390" src="http://www.youtube.com/embed/_y36fG2Oba0" frameborder="0" allowfullscreen></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2011/02/the-day-the-routers-died/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Puppet Modules &#8211; Debsecan</title>
		<link>http://code.geek.sh/2011/01/puppet-modules-debsecan/</link>
		<comments>http://code.geek.sh/2011/01/puppet-modules-debsecan/#comments</comments>
		<pubDate>Sun, 02 Jan 2011 17:43:12 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Unix / Linux]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Puppet]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=338</guid>
		<description><![CDATA[This is the first post of (hopefully) many, detailing some of my Puppet module implementations. Being the first, I thought I would start off with something simple. Debsecan The debsecan program evaluates the security status of a host running the Debian operation system. It reports missing security updates and known vulnerabilities in the programs which [...]]]></description>
			<content:encoded><![CDATA[<p>This is the first post of (hopefully) many, detailing some of my <a href="http://www.puppetlabs.com/" onclick="pageTracker._trackPageview('/outgoing/www.puppetlabs.com/?referer=');">Puppet</a> module implementations. Being the first, I thought I would start off with something simple.</p>
<p><strong>Debsecan</strong><br />
The <a href="http://www.enyo.de/fw/software/debsecan/" onclick="pageTracker._trackPageview('/outgoing/www.enyo.de/fw/software/debsecan/?referer=');">debsecan</a> program evaluates the security status of a host running the <a href="http://www.debian.org" onclick="pageTracker._trackPageview('/outgoing/www.debian.org?referer=');">Debian</a> operation system. It reports missing security updates and known vulnerabilities in the programs which are installed on the host.</p>
<p>This is a great package that I wanted installed on all <a href="http://www.debian.org" onclick="pageTracker._trackPageview('/outgoing/www.debian.org?referer=');">Debian</a> machines across my entire infrastructure. Thanks to Puppet, this is a breeze.</p>
<p><strong>Module layout</strong></p>
<pre class="brush: bash">
greg@codemine:~/code/puppet %> find modules/debsecan
modules/debsecan
modules/debsecan/files
modules/debsecan/files/debsecan
modules/debsecan/files/debsecan-cron
modules/debsecan/manifests
modules/debsecan/manifests/init.pp
</pre>
<p><strong>Manifest &#8211; init.pp</strong></p>
<pre class="brush: cpp">
greg@codemine:~/code/puppet %> cat modules/debsecan/manifests/init.pp
class debsecan {
    package { debsecan: ensure => latest }

    file {
        debsecan:
            path => "/etc/default/debsecan",
            owner => root,
            group => "root",
            mode => 644,
            source  => "puppet:///debsecan/debsecan",
            require => Package["debsecan"];
        debsecan-cron:
            path => "/etc/cron.d/debsecan",
            owner => root,
            group => "root",
            mode => 644,
            source  => "puppet:///debsecan/debsecan-cron",
            require => Package["debsecan"];
    }
}
</pre>
<p>There is really not much to this manifest. It essentially ensures debsecan is installed at the latest available version, it sets up my /etc/default/debsecan config and it ensures there is a cron entry to run it.</p>
<p><strong>Debsecan config</strong></p>
<pre class="brush: python">
greg@codemine:~/code/puppet %> cat modules/debsecan/files/debsecan
# Configuration file for debsecan.  Contents of this file should
# adhere to the KEY=VALUE shell syntax.  This file may be edited by
# debsecan's scripts, but your modifications are preserved.

# If true, enable daily reports, sent by email.
REPORT=true

# For better reporting, specify the correct suite here, using the code
# name (that is, "sid" instead of "unstable").
SUITE=lenny

# Mail address to which reports are sent.
MAILTO=root

# The URL from which vulnerability data is downloaded.  Empty for the
# built-in default.
SOURCE=
</pre>
<p><strong>Debsecan cron</strong></p>
<pre class="brush: python">
greg@codemine:~/code/puppet %> cat modules/debsecan/files/debsecan-cron
# cron entry for debsecan
MAILTO=root

42 * * * * daemon test -x /usr/bin/debsecan &#038;&#038; /usr/bin/debsecan --cron
# (Note: debsecan delays actual processing past 2:00 AM, and runs only
# once per day.)
</pre>
<p>You can grab a copy of all the above files (the complete module) here: <a href='http://code.geek.sh/wp-content/uploads/2010/12/debsecan-puppet.tar.gz'>debsecan-puppet.tar.gz</a></p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2011/01/puppet-modules-debsecan/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using ferm to build firewall rulesets</title>
		<link>http://code.geek.sh/2010/12/using-ferm-to-build-firewall-rulesets/</link>
		<comments>http://code.geek.sh/2010/12/using-ferm-to-build-firewall-rulesets/#comments</comments>
		<pubDate>Fri, 31 Dec 2010 16:18:07 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Unix / Linux]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Unix]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=302</guid>
		<description><![CDATA[This post is thanks to a suggestion from JP Viljoen to check out ferm. Well, I did, and it&#8217;s fairly neat. You get to express your firewall configuration in structures resembling simple C code along with using things like arrays, functions and if / else constructs which makes building complex rulesets quite a simple task. [...]]]></description>
			<content:encoded><![CDATA[<p>This post is thanks to a suggestion from <a href="http://twitter.com/froztbyte" onclick="pageTracker._trackPageview('/outgoing/twitter.com/froztbyte?referer=');">JP Viljoen</a> to check out <a href="http://ferm.foo-projects.org/" onclick="pageTracker._trackPageview('/outgoing/ferm.foo-projects.org/?referer=');">ferm</a>. Well, I did, and it&#8217;s fairly neat. You get to express your firewall configuration in structures resembling simple C code along with using things like arrays, functions and if / else constructs which makes building complex rulesets quite a simple task.</p>
<p>I&#8217;ve included an example configuration below of one of my machines. The network configuration is not extremely complex, but there is a mix of IPv4, IPv6 and &#8211; as this is an IRC server &#8211; some DNAT to make the IRC service available on a number of other privileged ports without having the service actually listen on those ports. This particular server is running Debian however ferm is basically just a front to ip(6)tables so it&#8217;ll run pretty much anywhere that runs.</p>
<p>First off, here is my network interface configuration to give you an idea of what is where:</p>
<pre class="brush: cpp">
kore:~# cat /etc/network/interfaces 

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 173.134.21.19             # Static eth0 IP
    netmask 255.255.255.0
    gateway 173.134.21.1

iface eth0 inet6 static
    address 2001:410:1e9b:ba22::2     # Primary HE.net IPv6 /64 address
    netmask 64

auto eth0:0
iface eth0:0 inet static
    address 192.168.49.97             # Local networking
    netmask 255.255.128.0

auto he-ipv6
iface he-ipv6 inet6 v4tunnel
    address 2001:410:1e9a:ba22::2     # Tunnel address
    netmask 64
    ttl 255
    gateway 2001:410:1e9a:ba22::1
    endpoint 216.218.224.42
    local 173.134.21.19
</pre>
<p>There is nothing extremely complicated here, just a basic IPv4 static IP assigned by my provider, a local network for traffic between this and other local nodes, a <a href="http://tunnelbroker.net/" onclick="pageTracker._trackPageview('/outgoing/tunnelbroker.net/?referer=');">Hurricane Electric IPv6 tunnel</a> and a static IP from my HE.net provided /64.</p>
<p>The ferm configuration in use here looks like this:</p>
<pre class="brush: cpp">
kore:~# cat /etc/ferm/ferm.conf
# -*- shell-script -*-
#
#  Configuration file for ferm(1).
#

@def $PORTS = (22 25 161 4949 6667 6668 7000 7352 7535); # Services running
@def $IRC_PORTS = (21 23 53 80 110 143 993);             # Additional ports

table filter {
    chain INPUT {
        policy DROP;

        # connection tracking
        mod state state INVALID DROP;
        mod state state (ESTABLISHED RELATED) ACCEPT;

        # allow local packages
        interface lo ACCEPT;

        # respond to ping
        proto icmp ACCEPT; 

        # standard ports we allow from the outside
        proto tcp dport $PORTS ACCEPT;
    }

    chain OUTPUT {
        policy ACCEPT;

        # connection tracking
        #mod state state INVALID DROP;
        mod state state (ESTABLISHED RELATED) ACCEPT;
    }

    chain FORWARD {
        policy DROP;

        # connection tracking
        mod state state INVALID DROP;
        mod state state (ESTABLISHED RELATED) ACCEPT;
    }
}

table nat {
    chain PREROUTING {
        # additional ports we listen on and redirect to the IRC server
        interface eth0 proto tcp dport $IRC_PORTS DNAT to 173.134.21.19:6667;
    }
}

# IPv6:
domain ip6 table filter {
    chain INPUT {
        policy DROP;

        # connection tracking
        mod state state INVALID DROP;
        mod state state (ESTABLISHED RELATED) ACCEPT;

        # allow ICMP (for neighbor solicitation, like ARP for IPv4)
        proto ipv6-icmp ACCEPT;

        # standard ports we allow from the outside
        proto tcp dport $PORTS ACCEPT;
    }

    chain OUTPUT {
        policy ACCEPT;

        # connection tracking
        #mod state state INVALID DROP;
        mod state state (ESTABLISHED RELATED) ACCEPT;
    }

    chain FORWARD {
        policy DROP;

        # connection tracking
        mod state state INVALID DROP;
        mod state state (ESTABLISHED RELATED) ACCEPT;
    }
}
</pre>
<p>So this ruleset is basically broken down into 3 parts:</p>
<ul>
<li>IPv4 filter table</li>
<li>IPv4 nat table</li>
<li>IPv6 filter table</li>
</ul>
<p><strong>IPv4 filter table</strong><br />
We control the INPUT, OUTPUT and FORWARD chains here. On the INPUT chain, we default to dropping everything, enable connection state tracking, allow all traffic through our local interface, allow ICMP and specify a list of ports we allow the outside world to use. On the OUTPUT chain we allow everything out and enable connection state tracking. Finally on the FORWARD chain we drop everything as this machine is not a router. Pretty concise right ?</p>
<p><strong>IPv4 nat table</strong><br />
In the nat table config, we basically setup the DNAT of those privileged ports under the PREROUTING chain.</p>
<p><strong>IPv6 filter table</strong><br />
Finally, in the IPv6 filter table, we allow the same set of incoming ports as IPv4, allow ipv6-icmp and setup connection state tracking as before.</p>
<p>Once that&#8217;s done, simply run:</p>
<p>kore:~# <strong>ferm /etc/ferm/ferm.conf</strong></p>
<p> &#8230; and your new ruleset is validated and loaded.<br />
<br/></p>
<p>On a side note, if you are interested in playing around with IPv6 I would highly recommend setting up a Hurricane Electric tunnel and then doing the <a href="http://ipv6.he.net/certification/" onclick="pageTracker._trackPageview('/outgoing/ipv6.he.net/certification/?referer=');">certification</a>. It makes for a great Saturday afternoon time waster and you might learn something along the way:<br />
<a href="http://ipv6.he.net/certification/" onclick="pageTracker._trackPageview('/outgoing/ipv6.he.net/certification/?referer=');"><img src="http://ipv6.he.net/certification/create_badge.php?pass_name=gregarmer&#038;badge=1" alt="IPv6 Certification" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2010/12/using-ferm-to-build-firewall-rulesets/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Natural order sorting strings with numbers</title>
		<link>http://code.geek.sh/2010/09/natural-order-sorting-strings-with-numbers/</link>
		<comments>http://code.geek.sh/2010/09/natural-order-sorting-strings-with-numbers/#comments</comments>
		<pubDate>Thu, 23 Sep 2010 19:29:42 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=308</guid>
		<description><![CDATA[The following python code makes natural sorting sequences of lexical and numerical values a little easier. It supports any iterable containing strings which have embedded numbers. In short it would give you this: foo1 < foo2 < foo10 instead of this: foo1 < foo10 < foo2 As an example, if you have this sequence: >>> [...]]]></description>
			<content:encoded><![CDATA[<p>The following python code makes natural sorting sequences of lexical and numerical values a little easier. It supports any iterable containing strings which have embedded numbers. In short it would give you this:</p>
<p>foo1 < foo2 < foo10</p>
<p>instead of this:</p>
<p>foo1 < foo10 < foo2</p>
<p>As an example, if you have this sequence:</p>
<pre class="brush: python">
>>> seq = ['foo', 'foo1', 'foo2', 'foo10', 'foobar10', '20', '100', '1', '3', 'bar1']
</pre>
<p>a regular sort would produce this:</p>
<pre class="brush: python">
>>> sorted(seq)
['1', '100', '20', '3', 'bar1', 'foo', 'foo1', 'foo10', 'foo2', 'foobar10']
</pre>
<p>whereas a natural sort would produce this:</p>
<pre class="brush: python">
>>> natural_sort(seq)
['1', '3', '20', '100', 'bar1', 'foo', 'foo1', 'foo2', 'foo10', 'foobar10']
</pre>
<p>Here is the code:</p>
<pre class="brush: python">
import re

def natsort_key(item):
    chunks = re.split('(\d+(?:\.\d+)?)', item)
    for ii in range(len(chunks)):
        if chunks[ii] and chunks[ii][0] in '0123456789':
            if '.' in chunks[ii]: numtype = float
            else: numtype = int
            chunks[ii] = (0, numtype(chunks[ii]))
        else:
            chunks[ii] = (1, chunks[ii])
    return (chunks, item)

def natural_sort(seq):
    sortlist = [item for item in seq]
    sortlist.sort(key=natsort_key)
    return sortlist
</pre>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2010/09/natural-order-sorting-strings-with-numbers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generating a dependency graph for a PostgreSQL database</title>
		<link>http://code.geek.sh/2010/07/generating-a-dependency-graph-for-a-postgresql-database/</link>
		<comments>http://code.geek.sh/2010/07/generating-a-dependency-graph-for-a-postgresql-database/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 14:25:16 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=276</guid>
		<description><![CDATA[This post was mostly inspired by this one, which shows how to generate a dependency graph for a MySQL database. Here we do something similar for PostgreSQL. This script will generate the required digraph data to pipe into graphviz dot which will generate a visual representation of dependencies in a database schema, based on foreign [...]]]></description>
			<content:encoded><![CDATA[<p>This post was mostly inspired by <a href="http://code.activestate.com/recipes/577298-plot-database-table-dependecies-for-a-mysql-databa/" onclick="pageTracker._trackPageview('/outgoing/code.activestate.com/recipes/577298-plot-database-table-dependecies-for-a-mysql-databa/?referer=');">this one</a>, which shows how to generate a dependency graph for a MySQL database. Here we do something similar for PostgreSQL.</p>
<p>This script will generate the required digraph data to pipe into <a href="http://www.graphviz.org/" target="_blank" onclick="pageTracker._trackPageview('/outgoing/www.graphviz.org/?referer=');">graphviz dot</a> which will generate a visual representation of dependencies in a database schema, based on foreign key constraints.</p>
<p>The script:</p>
<style type="text/css">
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
pre { line-height: 125%; }
body .hll { background-color: #ffffcc }
body  { background: #ffffff; }
body .c { color: #999988; font-style: italic } /* Comment */
body .err { color: #a61717; background-color: #e3d2d2 } /* Error */
body .k { font-weight: bold } /* Keyword */
body .o { font-weight: bold } /* Operator */
body .cm { color: #999988; font-style: italic } /* Comment.Multiline */
body .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
body .c1 { color: #999988; font-style: italic } /* Comment.Single */
body .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
body .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #aa0000 } /* Generic.Error */
body .gh { color: #999999 } /* Generic.Heading */
body .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
body .go { color: #888888 } /* Generic.Output */
body .gp { color: #555555 } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #aaaaaa } /* Generic.Subheading */
body .gt { color: #aa0000 } /* Generic.Traceback */
body .kc { font-weight: bold } /* Keyword.Constant */
body .kd { font-weight: bold } /* Keyword.Declaration */
body .kn { font-weight: bold } /* Keyword.Namespace */
body .kp { font-weight: bold } /* Keyword.Pseudo */
body .kr { font-weight: bold } /* Keyword.Reserved */
body .kt { color: #445588; font-weight: bold } /* Keyword.Type */
body .m { color: #009999 } /* Literal.Number */
body .s { color: #bb8844 } /* Literal.String */
body .na { color: #008080 } /* Name.Attribute */
body .nb { color: #999999 } /* Name.Builtin */
body .nc { color: #445588; font-weight: bold } /* Name.Class */
body .no { color: #008080 } /* Name.Constant */
body .ni { color: #800080 } /* Name.Entity */
body .ne { color: #990000; font-weight: bold } /* Name.Exception */
body .nf { color: #990000; font-weight: bold } /* Name.Function */
body .nn { color: #555555 } /* Name.Namespace */
body .nt { color: #000080 } /* Name.Tag */
body .nv { color: #008080 } /* Name.Variable */
body .ow { font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #009999 } /* Literal.Number.Float */
body .mh { color: #009999 } /* Literal.Number.Hex */
body .mi { color: #009999 } /* Literal.Number.Integer */
body .mo { color: #009999 } /* Literal.Number.Oct */
body .sb { color: #bb8844 } /* Literal.String.Backtick */
body .sc { color: #bb8844 } /* Literal.String.Char */
body .sd { color: #bb8844 } /* Literal.String.Doc */
body .s2 { color: #bb8844 } /* Literal.String.Double */
body .se { color: #bb8844 } /* Literal.String.Escape */
body .sh { color: #bb8844 } /* Literal.String.Heredoc */
body .si { color: #bb8844 } /* Literal.String.Interpol */
body .sx { color: #bb8844 } /* Literal.String.Other */
body .sr { color: #808000 } /* Literal.String.Regex */
body .s1 { color: #bb8844 } /* Literal.String.Single */
body .ss { color: #bb8844 } /* Literal.String.Symbol */
body .bp { color: #999999 } /* Name.Builtin.Pseudo */
body .vc { color: #008080 } /* Name.Variable.Class */
body .vg { color: #008080 } /* Name.Variable.Global */
body .vi { color: #008080 } /* Name.Variable.Instance */
body .il { color: #009999 } /* Literal.Number.Integer.Long */</p>
</style>
<p></head><br />
<body></p>
<h2></h2>
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">optparse</span> <span class="kn">import</span> <span class="n">OptionParser</span><span class="p">,</span> <span class="n">OptionGroup</span>

<span class="kn">import</span> <span class="nn">psycopg2</span>
<span class="kn">import</span> <span class="nn">sys</span>

<span class="k">def</span> <span class="nf">writedeps</span><span class="p">(</span><span class="n">cursor</span><span class="p">,</span> <span class="n">tbl</span><span class="p">):</span>
    <span class="n">sql</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;SELECT</span>
<span class="s">        tc.constraint_name, tc.table_name, kcu.column_name,</span>
<span class="s">        ccu.table_name AS foreign_table_name,</span>
<span class="s">        ccu.column_name AS foreign_column_name</span>
<span class="s">    FROM</span>
<span class="s">        information_schema.table_constraints AS tc</span>
<span class="s">    JOIN information_schema.key_column_usage AS kcu ON</span>
<span class="s">        tc.constraint_name = kcu.constraint_name</span>
<span class="s">    JOIN information_schema.constraint_column_usage AS ccu ON</span>
<span class="s">        ccu.constraint_name = tc.constraint_name</span>
<span class="s">    WHERE constraint_type = &#39;FOREIGN KEY&#39; AND tc.table_name = &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;&quot;&quot;</span>
    <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql</span> <span class="o">%</span> <span class="n">tbl</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cursor</span><span class="o">.</span><span class="n">fetchall</span><span class="p">():</span>
        <span class="n">constraint</span><span class="p">,</span> <span class="n">table</span><span class="p">,</span> <span class="n">column</span><span class="p">,</span> <span class="n">foreign_table</span><span class="p">,</span> <span class="n">foreign_column</span> <span class="o">=</span> <span class="n">row</span>
        <span class="k">print</span> <span class="s">&#39;&quot;</span><span class="si">%s</span><span class="s">&quot; -&gt; &quot;</span><span class="si">%s</span><span class="s">&quot; [label=&quot;</span><span class="si">%s</span><span class="s">&quot;];&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">tbl</span><span class="p">,</span> <span class="n">foreign_table</span><span class="p">,</span> <span class="n">constraint</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">get_tables</span><span class="p">(</span><span class="n">cursor</span><span class="p">):</span>
    <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;SELECT tablename FROM pg_tables WHERE schemaname=&#39;public&#39;&quot;</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cursor</span><span class="o">.</span><span class="n">fetchall</span><span class="p">():</span>
        <span class="k">yield</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">parser</span> <span class="o">=</span> <span class="n">OptionParser</span><span class="p">()</span>

    <span class="n">group</span> <span class="o">=</span> <span class="n">OptionGroup</span><span class="p">(</span><span class="n">parser</span><span class="p">,</span> <span class="s">&quot;Database Options&quot;</span><span class="p">)</span>
    <span class="n">group</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&quot;--dbname&quot;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">&quot;store&quot;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;dbname&quot;</span><span class="p">,</span>
            <span class="n">help</span><span class="o">=</span><span class="s">&quot;The database name.&quot;</span><span class="p">)</span>
    <span class="n">group</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&quot;--dbhost&quot;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">&quot;store&quot;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;dbhost&quot;</span><span class="p">,</span>
            <span class="n">default</span><span class="o">=</span><span class="s">&quot;localhost&quot;</span><span class="p">,</span>  <span class="n">help</span><span class="o">=</span><span class="s">&quot;The database host.&quot;</span><span class="p">)</span>
    <span class="n">group</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&quot;--dbuser&quot;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">&quot;store&quot;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;dbuser&quot;</span><span class="p">,</span>
            <span class="n">help</span><span class="o">=</span><span class="s">&quot;The database username.&quot;</span><span class="p">)</span>
    <span class="n">group</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&quot;--dbpass&quot;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s">&quot;store&quot;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;dbpass&quot;</span><span class="p">,</span>
            <span class="n">help</span><span class="o">=</span><span class="s">&quot;The database password.&quot;</span><span class="p">)</span>
    <span class="n">parser</span><span class="o">.</span><span class="n">add_option_group</span><span class="p">(</span><span class="n">group</span><span class="p">)</span>

    <span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">options</span><span class="o">.</span><span class="n">dbname</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Please supply a database name, see --help for more info.&quot;</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="n">psycopg2</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s">&quot;dbname=&#39;</span><span class="si">%s</span><span class="s">&#39; user=&#39;</span><span class="si">%s</span><span class="s">&#39; host=&#39;</span><span class="si">%s</span><span class="s">&#39; password=&#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span>
            <span class="o">%</span> <span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">dbname</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">dbuser</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">dbhost</span><span class="p">,</span> <span class="n">options</span><span class="o">.</span><span class="n">dbpass</span><span class="p">))</span>
    <span class="k">except</span> <span class="n">psycopg2</span><span class="o">.</span><span class="n">OperationalError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Failed to connect to database,&quot;</span><span class="p">,</span>
        <span class="k">print</span> <span class="s">&quot;perhaps you need to supply auth details:</span><span class="se">\n</span><span class="s"> </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
        <span class="k">print</span> <span class="s">&quot;Use --help for more info.&quot;</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

    <span class="k">print</span> <span class="s">&quot;Digraph F {</span><span class="se">\n</span><span class="s">&quot;</span>
    <span class="k">print</span> <span class="s">&#39;ranksep=1.0; size=&quot;18.5, 15.5&quot;; rankdir=LR;&#39;</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">get_tables</span><span class="p">(</span><span class="n">cursor</span><span class="p">):</span>
        <span class="n">writedeps</span><span class="p">(</span><span class="n">cursor</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
    <span class="k">print</span> <span class="s">&quot;}&quot;</span>

    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre>
</div>
<p>You could run it as follows:</p>
<pre>
python postgres-deps.py --dbname some_database | dot -Tpng > deps.png
</pre>
<p><strong>Note</strong>: for other options use:</p>
<pre>python postgres-deps.py --help</pre>
<p>That should spit out one of these:</p>
<p><img src="http://code.geek.sh/wp-content/uploads/2010/07/deps.png" alt="deps" title="deps" width="778" height="299" class="alignnone size-full wp-image-287" /></p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2010/07/generating-a-dependency-graph-for-a-postgresql-database/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting Git manpages on OS X</title>
		<link>http://code.geek.sh/2010/04/getting-git-manpages-on-os-x/</link>
		<comments>http://code.geek.sh/2010/04/getting-git-manpages-on-os-x/#comments</comments>
		<pubDate>Thu, 15 Apr 2010 14:58:13 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Unix / Linux]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[Mac]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=272</guid>
		<description><![CDATA[For some reason the OS X install of Git doesn&#8217;t include the manpages. Here is how I installed them. First off, find the appropriate manpath. greg@codemine:~ %> cat /etc/manpaths /usr/share/man /usr/local/share/man /usr/local/share/man looks good&#8230; greg@codemine:~ %> VER=`git --version &#124; awk '{print $3}'` greg@codemine:~ %> curl -O http://www.kernel.org/pub/software/scm/git/git-manpages-$VER.tar.bz2 % Total % Received % Xferd Average Speed [...]]]></description>
			<content:encoded><![CDATA[<p>For some reason the OS X install of Git doesn&#8217;t include the manpages. Here is how I installed them.</p>
<p>First off, find the appropriate manpath.</p>
<pre class="brush: plain">
greg@codemine:~ %> cat /etc/manpaths
/usr/share/man
/usr/local/share/man
</pre>
<p>/usr/local/share/man looks good&#8230;</p>
<pre class="brush: plain">
greg@codemine:~ %> VER=`git --version | awk '{print $3}'`
greg@codemine:~ %> curl -O http://www.kernel.org/pub/software/scm/git/git-manpages-$VER.tar.bz2
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  242k  100  242k    0     0  92051      0  0:00:02  0:00:02 --:--:--   99k
greg@codemine:~ %> sudo tar xjv -C /usr/local/share/man -f git-manpages-$VER.tar.bz2
Password:
x ./
x ./man1/
x ./man1/git-add.1
[snip]
x ./man7/gitworkflows.7
greg@codemine:~ %> rm git-manpages-$VER.tar.bz2
greg@codemine:~ %>
</pre>
<p>&#8220;man git-add&#8221; should now work fine.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2010/04/getting-git-manpages-on-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extending Python with modules written in C</title>
		<link>http://code.geek.sh/2009/12/extending-python-with-modules-written-in-c/</link>
		<comments>http://code.geek.sh/2009/12/extending-python-with-modules-written-in-c/#comments</comments>
		<pubDate>Sat, 26 Dec 2009 21:14:54 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://code.geek.sh/?p=164</guid>
		<description><![CDATA[Using C (or C++) to create Python modules is really quite simple, providing you know a little C of course. I recently had to do some work around getting a bunch of legacy C code talking to a newer system and thought I&#8217;d post a nice simple example of how the Python extensions work. This [...]]]></description>
			<content:encoded><![CDATA[<p>Using C (or C++) to create Python modules is really quite simple, providing you know a little C of course. I recently had to do some work around getting a bunch of legacy C code talking to a newer system and thought I&#8217;d post a nice simple example of how the Python extensions work.</p>
<p>This code gives you a single method &#8220;do()&#8221; that will print the output of a command, passed to it as a string, to stdout and return the exit code as a python int.</p>
<p>Dump this into &#8220;mycmd.c&#8221;:</p>
<style type="text/css">
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
pre { line-height: 125%; }
body .hll { background-color: #ffffcc }
body  { background: #ffffff; }
body .c { color: #999988; font-style: italic } /* Comment */
body .err { color: #a61717; background-color: #e3d2d2 } /* Error */
body .k { font-weight: bold } /* Keyword */
body .o { font-weight: bold } /* Operator */
body .cm { color: #999988; font-style: italic } /* Comment.Multiline */
body .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
body .c1 { color: #999988; font-style: italic } /* Comment.Single */
body .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
body .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
body .ge { font-style: italic } /* Generic.Emph */
body .gr { color: #aa0000 } /* Generic.Error */
body .gh { color: #999999 } /* Generic.Heading */
body .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
body .go { color: #888888 } /* Generic.Output */
body .gp { color: #555555 } /* Generic.Prompt */
body .gs { font-weight: bold } /* Generic.Strong */
body .gu { color: #aaaaaa } /* Generic.Subheading */
body .gt { color: #aa0000 } /* Generic.Traceback */
body .kc { font-weight: bold } /* Keyword.Constant */
body .kd { font-weight: bold } /* Keyword.Declaration */
body .kn { font-weight: bold } /* Keyword.Namespace */
body .kp { font-weight: bold } /* Keyword.Pseudo */
body .kr { font-weight: bold } /* Keyword.Reserved */
body .kt { color: #445588; font-weight: bold } /* Keyword.Type */
body .m { color: #009999 } /* Literal.Number */
body .s { color: #bb8844 } /* Literal.String */
body .na { color: #008080 } /* Name.Attribute */
body .nb { color: #999999 } /* Name.Builtin */
body .nc { color: #445588; font-weight: bold } /* Name.Class */
body .no { color: #008080 } /* Name.Constant */
body .ni { color: #800080 } /* Name.Entity */
body .ne { color: #990000; font-weight: bold } /* Name.Exception */
body .nf { color: #990000; font-weight: bold } /* Name.Function */
body .nn { color: #555555 } /* Name.Namespace */
body .nt { color: #000080 } /* Name.Tag */
body .nv { color: #008080 } /* Name.Variable */
body .ow { font-weight: bold } /* Operator.Word */
body .w { color: #bbbbbb } /* Text.Whitespace */
body .mf { color: #009999 } /* Literal.Number.Float */
body .mh { color: #009999 } /* Literal.Number.Hex */
body .mi { color: #009999 } /* Literal.Number.Integer */
body .mo { color: #009999 } /* Literal.Number.Oct */
body .sb { color: #bb8844 } /* Literal.String.Backtick */
body .sc { color: #bb8844 } /* Literal.String.Char */
body .sd { color: #bb8844 } /* Literal.String.Doc */
body .s2 { color: #bb8844 } /* Literal.String.Double */
body .se { color: #bb8844 } /* Literal.String.Escape */
body .sh { color: #bb8844 } /* Literal.String.Heredoc */
body .si { color: #bb8844 } /* Literal.String.Interpol */
body .sx { color: #bb8844 } /* Literal.String.Other */
body .sr { color: #808000 } /* Literal.String.Regex */
body .s1 { color: #bb8844 } /* Literal.String.Single */
body .ss { color: #bb8844 } /* Literal.String.Symbol */
body .bp { color: #999999 } /* Name.Builtin.Pseudo */
body .vc { color: #008080 } /* Name.Variable.Class */
body .vg { color: #008080 } /* Name.Variable.Global */
body .vi { color: #008080 } /* Name.Variable.Instance */
body .il { color: #009999 } /* Literal.Number.Integer.Long */</p>
</style>
<pre><span class="cp">#include &lt;Python.h&gt;</span>

<span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">mycmd_do</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">command</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">sts</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTuple</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="s">&quot;s&quot;</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">command</span><span class="p">))</span>
        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="n">sts</span> <span class="o">=</span> <span class="n">system</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">Py_BuildValue</span><span class="p">(</span><span class="s">&quot;i&quot;</span><span class="p">,</span> <span class="n">sts</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="n">PyMethodDef</span> <span class="n">MyCmdMethods</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">{</span><span class="s">&quot;do&quot;</span><span class="p">,</span> <span class="n">mycmd_do</span><span class="p">,</span> <span class="n">METH_VARARGS</span><span class="p">,</span> <span class="s">&quot;Print output of &#39;cmd&#39;, return exit code.&quot;</span><span class="p">},</span>
    <span class="p">{</span><span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">}</span>        <span class="cm">/* Sentinel */</span>
<span class="p">};</span>

<span class="n">PyMODINIT_FUNC</span>
<span class="nf">initmycmd</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="n">Py_InitModule</span><span class="p">(</span><span class="s">&quot;mycmd&quot;</span><span class="p">,</span> <span class="n">MyCmdMethods</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
    <span class="n">Py_SetProgramName</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="n">Py_Initialize</span><span class="p">();</span>
    <span class="n">initmycmd</span><span class="p">();</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span></pre>
<p>Great, so we have some example code now, here is how you build an importable module with it:</p>
<pre>greg@codemine:~/code/mycmd %&gt; cc -dynamic -g -Wall -I/System/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 -c mycmd.c -o mycmd.o
greg@codemine:~/code/mycmd %&gt; cc -bundle -undefined dynamic_lookup mycmd.o -o mycmd.so</pre>
<p><strong>Note:</strong> Don&#8217;t forget to replace the include path above with the correct path to Python.h on your machine.</p>
<p>This should give you a mycmd.so on unix / linux and a mycmd.dll on windows. In the same directory, run a python interpreter and test it out.</p>
<pre>greg@codemine:~/code/mycmd %&gt; python
Python 2.6.3 (r263:75183, Nov  4 2009, 12:53:19)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; import mycmd
&gt;&gt;&gt; mycmd.do('/usr/bin/false')
256
&gt;&gt;&gt; mycmd.do('/usr/bin/true')
0
&gt;&gt;&gt; mycmd.do('uname -a')
Darwin codemine.codelounge.int 10.2.0 Darwin Kernel Version 10.2.0: Tue Nov  3 10:37:10 PST 2009; root:xnu-1486.2.11~1/RELEASE_I386 i386
0
&gt;&gt;&gt;</pre>
<p>There is much more you can do around this, thankfully the <a href="http://docs.python.org/extending/" onclick="pageTracker._trackPageview('/outgoing/docs.python.org/extending/?referer=');">documentation</a> is remarkably good.</p>
<p>There is not much to the actual code. First, we define the C function that will handle our command &#8220;mycmd_do&#8221;. Then we set up an array of methods we want to expose to python &#8220;MyCmdMethods&#8221;. We then setup an initializer &#8220;initmycmd&#8221; to expose the module which is executed from &#8220;main&#8221; after the python initializer &#8220;Py_Initialize&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.geek.sh/2009/12/extending-python-with-modules-written-in-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

