Monitoring Processes on the Command Line

Date

Updated 2012-11-06 with an alternative.

Sometimes you have a long running process that is firing off many commands in a row and you don’t get much output from the command. I like to have an idea of what’s happening, so I employ a simple Bash script that I’ve hand typed a million times. It keeps just the data I want on screen and auto-updates ever couple of seconds, so I can keep an eye on it while I’m working.

while true
do
    # Some command goes here
    sleep 2
    clear
done

If you have any modern shell, you can type this in with the line breaks. Now I have a clear console that is showing me just the data I want.

How do I use this? Right now, I have an apt-mirror post mirror script that rsyncs multiple directories. This is an automated process that runs quietly, so I can use ps -ef | grep rsync to monitor the process. I’ve also used this to monitor massive file creation / deletions, so the command could be ls -l | wc -l to count the files in the director. I use Hylafax, so I can monitor the modems with faxstat -a.

An Alternative

After posting this article, it was brought to my attention that I could just use the watch command. As with a lot of complex technologies, you tend to learn to do something one way and stay oblivious to other possible ways. watch is part of the procps project, so instead of the above loop, you could use:

watch "ps -ef | grep rsync"

This by default runs the given command every 2 seconds. Check out the man page for more options.

Unfortunately, watch is not part of the default UNIX stack on OS X. It seems to be available in Homebrew, but since it isn’t already on my system, I’ll probably stick with the bash script. Old habits die hard.


Stack's Score Card 1.0.1 Available

Date

Version 1.0.1 of Stack’s Score Card has been released. This is a maintenance release that does the following:

  • Fixes for iOS 6 and iPhone 5
  • Fixed a focusing bug when modifying scores
  • Old games are cleaned out on start up

Stack's Score Card 1.0 Now Available

Date

The initial release of Stack’s Score Card is now available. 1.0 is a core release. Much more will be added in time.

Version 1.0.1 has already been submitted to the App Store to address issues with iOS 6 and iPhone 5.

More info about Stack’s Score Card can be found here


"Cheating" at Words With Friends

Date

It’s time to admin something. I cheat at Words With Friends. I only justify it with the fact that I at least wrote the code to help me cheat.

And cheat really isn’t the word for it. Sometimes I just stare at my letter rack for hours and come up with nothing. I wrote the following script just to get my brain going. You have two options with this script. Argument 1 always has to be your letter rack. You can use the “+” sign for the blank tile. Argument 2 is regular expression if you are looking for something specific.

If you have the tile rack aabbccd, you would run words-help aabbccd and get a dump of every combination. If you are looking for words with ba at the beginning of the word, you would run words-help aabbccd ^ba.

This script should work on anything UNIX-like that has a dictionary file at /usr/share/dict/words. You can edit the script as you need.

#!/usr/bin/env ruby

WORDS_FILE = '/usr/share/dict/words'

class Engine

  def initialize(file)
    @file = file

    read_dictionary
  end

  def go(letters, regex = nil) 
    @letters = letters.split ''
    @regex = Regexp.new(regex) unless regex.nil?
    @words = []

    # Find the words
    letter_combinations do |letter_combination|
      letter_combination.permutation.to_a.each do |letter_array|
        word = letter_array.join('')
        if @dictionary.key?(word)
          if @regex.nil?
            @words << word
          else
            @words << word if @regex.match(word)
          end
        end
      end
    end

    # Clean up
    @words.sort.uniq
  end

  private

  def letter_combinations
    max = (2 ** @letters.count) - 1
    1.upto(max) do |i|
      word = []
      mask = sprintf("%0#{@letters.count}b", i).split('')
      mask.each_with_index do |bit, i|
        word << @letters[i] if bit == '1'
      end

      # Substitute wild cards
      idx = word.index '+'
      if idx.nil?
        yield word
      else
        ('a'..'z').each do |l|
          word[idx] = l
          yield word
        end
      end
    end
  end

  def read_dictionary
    # Build the dictionary
    @dictionary = {}

    # Read the words
    File.open(@file, 'r') do |file|
      file.each_line do |line|
        line.strip!

        # Skip proper nouns
        next if line =~ /[A-Z]/

        # Skip 1 letter words
        next if line.length == 1

        # Add the word to the dictionary
        @dictionary[line] = 1
      end
    end
  end

end

if ARGV.length < 1 || ARGV.length > 2
  $stderr.puts "Letters are required"
  exit
end

e = Engine.new WORDS_FILE
e.go(ARGV[0], ARGV[1]).each { |word| puts word }

This script is brute force, so the more letters you set as Argument 1, the longer it will take to run. You’ve been warned.


Making an Image-Flip Proxy

Date

There have been many articles about creating a proxy server that flips directly as a proxy or gateway server. or distorts images that pass through it. They are hilarious, but they tended to lack in certain details. This article will detail how to set up the OS, proxy and routing, giving you the option to either use it

This is also very quick and dirty. It is meant to get you started as quickly as possible. This means any longevity or security concerns are ignored. You have been warned.

The original idea came from here.

Setting Up An OS

The proxy is based off of a default install of Debian Lenny from the netinstall ISO. It can be found here.

For the OS install, you can accept the defaults for almost every option. There are two cases to watch out for. First, you will be prompted to confirm all of your partitioning options before proceeding. The default option is to cancel. The second case is the additional software options. I unchecked the “Desktop Environment” option, since this is going to be server.

Once the OS is installed, log in as root and run the following commands to prepare our environment:

apt-get install squid3 apache2 imagemagick  
chmod -R 777 /var/www

Configuring the Proxy

Open the /etc/squid3/squid.conf file in your favorite editor. Near the top of the file is a configuration option for http_port. Change it to look like the following:

http_port 3128 transparent

Next, find the line that begins with INSERT YOUR OWN RULE(S), which should be around line number 2138. Below that line, add the following to allow your private network access to your proxy. Make sure to change the it for your network.

acl lan src 192.168.1.0/24  
http_access allow lan

Lastly, go to the bottom of the file and add the following line. This is the magic which will flip the images for you.

redirect_program /usr/local/bin/flip.pl

Save the file and exit your editor.

The Flip Script

Edit the file /usr/local/bin/flip.pl and add the following to it:

#!/usr/bin/perl

$|=1;  
$count = 0;  
$pid = $$;  
while (<>) {  
    chomp $_;  
    if ($_ =~ /(.*)(\.jpg|\.png|\.gif)/i) {  
        $url = $1 . $2;  
        system("/usr/bin/wget", "-q", "-O","/var/www/$pid-$count$2", "$url");  
        system("/usr/bin/mogrify", "-flip","/var/www/$pid-$count$2");  
        system("/bin/chmod", "777", "/var/www/$pid-$count$2");  
        print "http://127.0.0.1/$pid-$count$2\n";  
    } else {  
        print "$_\n";  
    }  
    $count++;  
}

The script is fairly simple. Squid passes URL’s to the script. If the URL ends in image type, it is pulled down to root of our web server. Mogrify then modifies the image in place. Lastly, it tells Squid to pull the image from our web server instead of the internet. If the URL isn’t an image, we just dump the origin URL back out.

Once the file is in place, make sure to make it executable.

chmod +x /usr/local/bin/flip.pl

You should have enough to test. Restart Squid with the following:

invoke-rc.d squid3 restart

You can now set up any browser to use the server as a proxy on port

  1. If you visit a page you have been to before, make sure you refresh a couple of times. Your browser might have cached the images locally, which means they won’t go through our proxy.

Making A Transparent Gateway

The last part of the process is to make the server a gateway which will transparently redirect web requests through the proxy. Create the file /etc/network/if-up.d/00-firewall and add the following to it:

#!/bin/sh

PATH=/usr/sbin:/sbin:/bin:/usr/bin

#  
# delete all existing rules.  
#  
iptables -F  
iptables -t nat -F  
iptables -t mangle -F  
iptables -X

# Always accept loopback traffic  
iptables -A INPUT -i lo -j ACCEPT

# Allow established connections  
iptables -A INPUT -m state --state ESTABLISHED,RELATED,NEW -j ACCEPT  
iptables -A FORWARD -i eth0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow outgoing connections  
iptables -A FORWARD -i eth0 -o eth0 -j ACCEPT

# Masquerade  
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE  
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128

echo 1 > /proc/sys/net/ipv4/ip_forward

Now make the script executable and restart the networking.

chmod +x /etc/network/if-up.d/00-firewall  
invoke-rc.d networking restart

At this point, you should be able to set any computer’s default gateway to the IP address of your server. You don’t need to set a proxy address for your browser. Everything is now routed and all HTTP requests are redirected through the proxy.