mebubo

Config files. Encapsulation of knowledge.

I am a control freak. I like control. I like automation. That’s why I try as much as possible to use software with human-editable config files. I store those files in a git repository. Thanks to it, I’m able to keep my settings in sync across all the machines I use. And the time it takes to setup a new machine is minutes, not hours.

I suppose you could call this approach — human-editable config files, scripts that automate tasks — an encapsulation of knowledge.

You are faced with a software-configuration-related problem: how do I make some piece of software behave the way I want? It might take you hours of googling and reading manuals, but once you’ve figured it out, you should be done. Provided that you were able to formalize your solution in a form of a config file or a script, you will never have to revisit the same problem, ever! All the knowledge you need sits right there in a file in your git repository.

And as long as the configuration is in a human-editable format, you will be able to extend it in the future, but you’ll never have to remember how to do exactly the same thing if you already did it once.

That is of course almost impossible with GUI-based configuration tools. There, you just have to go through the pain again, again and again. Eclipse IDE is a good example, that’s why I hate its approach to configuration with passion.

Some software like the Chromium browser tries to solve this problem by auto-synchronization of the (GUI-configured) settings across all instances of the application, but that is clearly not enough. I want a common system that works for everything that I use, not some special mechanism for every piece of software. And I want more control and flexibility! Chromium for example does not allow me to have slightly different settings for home and work. For software such as Emacs I can easily achieve that using a condition on the hostname in my config file or using git branches and merging to maintain several slightly different versions.

That is why the only piece of my Chromium configuration I feel confident about (the only one that is in a configuration file that I myself put there) is the user style sheet to display Gmail in monospace font. Everything else is handled by Chromium; it is not in the repo, it is out of my control, so I might have to repeat it one day.

The opposite of that is my Emacs configuration. It is all there, always ready to be extended, but never — to be repeated.

Building tmux statically

Here is what I had to do to build tmux 1.6 statically on Debian wheezy:

$ LDFLAGS="-static" LIBS="-lcurses -ltinfo" ./configure
$ make

Bluetooth tethering with blues-tools and Cyanogenmod

I have to admit that I kind of like Bluetooth technology. It works great for a wireless mouse, and I also use it to tether my Android phone which is running Cyanogenmod 7.2. Here is how.

First, we need to pair the devices, the process which I have already described. To recap:

$ bt-adapter -d   # note the MAC address in the output
$ bt-device -c <MAC address>
$ bt-device --set <MAC address> Alias desire

Here I’ve chosen “desire” as an alias for my phone (it’s an HTC Desire). Once the devices are paired, the rest is easy. The important command is bt-network -c <alias> nap. I’ve written a small script to wait for bluetooth connection and to launch dhcp client once it is established:

#!/bin/sh

DHCP_CMD="sudo dhclient -d bnep0"
BT_CMD="bt-network -c desire nap"
RETRIES=10
CONNECTED="Network service is connected"

out=/tmp/bt-network.out.$$

trap cleanup TERM INT EXIT

$BT_CMD >$out 2>&1 &
bt_pid=$!

cleanup () {
    rm $out > /dev/null 2>&1
}

echo -n "*** Waiting for bluetooth connection..."

for i in $(seq $RETRIES); do
    if grep "$CONNECTED" $out >/dev/null 2>&1; then
        echo "\n*** Bluetooth connection established:\n"
        cat $out
        echo "\n*** Running dhcp client:\n"
        $DHCP_CMD
        break
    fi
    if [ ! -d /proc/$bt_pid ]; then
        echo "\n*** Bluetooth connection died, exiting. Output:\n"
        cat $out
        exit 1
    fi
    sleep 1
    echo -n "$i "
done

Here is the normal output of the script:

$ ./bt-tether.sh
*** Waiting for bluetooth connection...1 2 3 4
*** Bluetooth connection established:

Network service is connected
Interface: bnep0
UUID: NAP (00001116-0000-1000-8000-00805f9b34fb)

*** Running dhcp client:

Internet Systems Consortium DHCP Client 4.2.2
Copyright 2004-2011 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/bnep0/cc:af:78:e4:e3:ef
Sending on   LPF/bnep0/cc:af:78:e4:e3:ef
Sending on   Socket/fallback
DHCPREQUEST on bnep0 to 255.255.255.255 port 67
DHCPACK from 192.168.43.1
bound to 192.168.43.78 -- renewal in 1520 seconds.

And here is the notification that appears on the phone screen once the connection is established:

Update 11 May 2013

I recently realized that, at least on a Debian system, the shell script above is not really necessary.

Instead, add the following 2 lines to the /etc/network/interfaces file:

allow-hotplug bnep0
iface bnep0 inet dhcp

To start the tethering, simply use the bt-network command directly:

bt-network -c <alias> nap

As soon as the bluetooth network interface bnep0 appears, it will be auto-configured with dhcp thanks to the entry in the /etc/network/interfaces file.

Bluetooth mouse in linux using blues-tools

Configuring a bluetooth mouse is easy with the excellent bluez-tools package.

First we need to discover the MAC address of the mouse. To do this, press the button on the mouse labeled "connect" or something similar, then issue the following command:

$ bt-adapter -d

You should see the output similar to the following:

Searching...

[00:01:02:03:04:05]
  Name: Bluetooth Laser Travel Mouse
  Alias: mouse
  Address: 00:01:02:03:04:05
...

Next we'll connect to the mouse (replace 00:01:02:03:04:05 with the MAC adress you saw in the output of the previous command):

$ bt-device -c 00:01:02:03:04:05
Connecting to: 00:01:02:03:04:05
Agent registered
Device: Bluetooth Laser Travel Mouse (00:01:02:03:04:05)
Enter PIN code: 0000
Agent released
Done

You'll be asked to enter the PIN code; "0000" worked in my case.

Now we can see our mouse in the list of known devices:

$ bt-device -l
Added devices:
Bluetooth Laser Travel Mouse (00:01:02:03:04:05)

Let's give it a shorter alias:

$ bt-device --set 00:01:02:03:04:05 Alias mouse
Alias: Bluetooth Laser Travel Mouse -> mouse

From now on, we can use the alias instead of the MAC address in the command line.

In my experience, setting the Trusted property is necessary for mouse to be able to reconnect automatically:

$ bt-device --set mouse Trusted true
Trusted: 0 -> 1

The only thing that remains is to connect the input service. The bt-input command does just that:

$ bt-input -c mouse
Input service is connected

That's it! After this, the mouse works all the time, including after reboot or sleep. All you need to do is move your mouse, and it reconnects within a second.

Using Huawei E1550 3G modem in Debian

I use this nice little 3G modem from time to time whenever I'm away from home and work. Here's how it works in Debian.

ZeroCD, modeswitch

First of all, this modem uses the so called ZeroCD mode to facilitate driver installation in Windows. When plugged in, it acts as a USB CDROM, from which the mobile provider-branded Windows software can be installed. The Windows software then performs some special action to put the modem into the actual "modem mode" (in which it even has different USD IDs).

This ZeroCD feature is of course completely unnecessary and even annoying in linux.

When first plugged in, the modem shows up like this:

$ lsusb
Bus 003 Device 004: ID 12d1:1446 Huawei Technologies Co., Ltd. E1552 (HSPA modem)

To switch the mode, I used the modem-modeswitch binary that used to be included in the udev package:

$ sudo ./modem-modeswitch --vendor 0x12d1 --product 0x1446 --type option-zerocd

After that, lsusb output changes to

$ lsusb
Bus 003 Device 005: ID 12d1:1001 Huawei Technologies Co., Ltd. E620 USB Modem

and the /dev/ttyUSB0 device file is created by udev. This file is used to communicate with the modem.

Apparently, instead of the deprecated modem-modeswitch from udev, the usb-modeswitch Debian package can be installed in order to automatically switch the device into the modem mode every time it is plugged in, but I never used it. I opted for disabling ZeroCD altogether.

Disabling ZeroCD

Since I didn't plan to use this modem in Windows, I wanted to disable the ZeroCD feature completely. It is possible to change the default state of the device using the following AT commands (found here):

AT^U2DIAG=0   -- modem
AT^U2DIAG=1   -- modem + CD-ROM
AT^U2DIAG=255 -- modem + CD-ROM + Card Reader
AT^U2DIAG=256 -- modem + Card Reader

AT commands can be entered interactively using your favorite serial communication program, for instance picocom:

$ picocom /dev/ttyUSB0

I chose the value 256 to be able to use both the modem and the built-in microSD card reader. Once the command is entered, no mode switching is necessary any more.

Entering PIN

I prefer to leave my SIM-card PIN-locked. I use the following udev rule to run the script that automatically unlocks the card every time I plug the modem in:

$ cat /etc/udev/rules.d/45-huawei1550.rules
SUBSYSTEM=="usb", ACTION=="add", ATTR{idProduct}=="1001", ATTR{idVendor}=="12d1", RUN+="/usr/local/sbin/modem-pin.sh"

Here is the content of the /usr/local/sbin/modem-pin.sh script:

#!/bin/sh

RETRIES=10
PORT=/dev/ttyUSB0

PIN=1234

# wait for $PORT to appear
for i in `seq $RETRIES`
do
    if [ -e $PORT ]
    then
        # enter the PIN
        echo -e "AT+CPIN=${PIN}\r" > $PORT
        break
    fi
    sleep 1
# backgrounding is necessary for udev to proceed with creating the
# device file
done &
Once the modem is plugged in and the SIM card is unlocked, we're ready to connect.

pppd one-liner

The connection can be established with a single command, no need to edit any config files. Change APN name ("internet") and phone number ("*99#") to the ones appropriate for your provider:

$ /usr/sbin/pppd connect "/usr/sbin/chat -v ECHO ON '' AT+CGDCONT=1,\\\"IP\\\",\\\"internet\\\" OK ATDT*99# CONNECT" /dev/ttyUSB0 nodetach usepeerdns defaultroute noipdefault noauth

I found this one-liner to be great for debugging.

Permanent pppd and chat configuration

The last step is to put pppd and chat configuration into static files. It is pretty straightforward and I'll leave it as an excercise for the reader :).