a blog by Marius Gedminas

Serving ePub files to Android 1.6

If you click on an ePub download link in the Android browser and get back an error saying "Cannot download. The content type is not supported on the device", then make sure the web server is setting the Content-Type header to "application/epub+zip" and not "application/octet-stream". When you do this, Android will launch FBReaderJ automatically (provided that you have it installed, of course).

N900 connection sharing the hard way

My N900 has a SIM card with a flat-rate 3G data plan. My laptop hasn't. What do I do when I want to use the Internet on my laptop somewhere that doesn't have WiFi? Well, there are many options:

Option 1: N900 as a USB modem

Use the provided USB cable to connect the N900 to the laptop. Choose "PC Suite" mode on the N900 when you get the USB connection menu. The laptop now sees your N900 as a bog-standard USB 3G modem. Use Network Manager to connect to the internet.

Pros: no extra setup required. The N900 and the laptop can both access the Internet at the same time.

Cons: you have to use a USB cable (I hate cables). You cannot ssh into your N900 (and ssh is my primary file transfer protocol between the laptop and the M900).

Option 2: N900 as a Bluetooth DUN modem

Install Bluetooth DUN support from Maemo Extras. Then use it like you would any other phone that has Bluetooth DUN.

Pros: no cables.

Cons: Bluetooth is the worst technology ever. I never had it work reliably. Plus, Network Manager in Ubuntu 10.04 doesn't support Bluetooth DUN (it supports only Bluetooth PAN, as far as I know).

Option 3: N900 as a WiFi access point with Joikuspot

I haven't tried this.

Pros: simple (hopefully), no cables required.

Cons: Joikuspot is non-free. I'm not an absolute zealot, but I will avoid closed-source stuff when open-source alternatives are available.

Option 4: N900 as a WiFi access point with Mobilehotspot

I haven't tried this either.

Pros: it's an open-source app available from Maemo Extras. No cables required.

Cons: requires a non-standard kernel (or so I've heard). Way outside my comfort level.

Option 5: N900 as a WiFi access point with shell scripts

Here's the shell script I run on my N900: share-wifi. It sets up an ad-hoc WiFi network, and starts a DHCP and DNS server (dnsmasq). Sadly, it cannot set up connection sharing (NAT), so I rely on OpenSSH as a SOCKS5 proxy. The whole setup is like this:

  1. You want the latest firmware (PR 1.2) to avoid this bug.
  2. You need to have OpenSSH installed on the N900. Also, setting up key-based authentication makes it more convenient.
  3. The script assumes that you've set up sudo on the N900 so that you can run any command as root.
  4. You need to have wireless-tools installed. It's in the main SSU repository so you should be able to sudo apt-get install it (if it's not preinstalled; I don't remember).
  5. On the N900 run share-wifi in a terminal (optionally passing a WiFi channel number from 1 to 11, in case you need to avoid interference with nearby networks).
  6. On the laptop connect to the new n900 WLAN and run ssh -D 1080 user@n900. You will get a shell session; the SOCKS proxy will be active while it is open.
  7. Reconfigure your laptop to use a SOCKS5 proxy on localhost:1080. For GNOME systems I've a couple of shell scripts: proxy-on and proxy-off. For applications that do not use the GNOME proxy settings (such as Subversion access over SSH), use tsocks.
  8. When done, hit Ctrl-C on the N900 to terminate the sharing script.

Pros: no non-free software or custom kernel required. No cables.

Cons: complicated to set up. No WLAN power savings available for ad-hoc networks, so battery life is extremely poor (~2 hours). But, hey, no cables!

ImportError: No module named _md5

If you're using virtualenv, and after a system upgrade you get errors like

...
  File "...", line ...
    from hashlib import md5
  File "/usr/lib/python2.6/hashlib.py", line 63, in __get_builtin_constructor
     import _md5
ImportError: No module named _md5

this means that the copy of the python executable in your virtualenv/bin directory is outdated and you should update it:

$ cp /usr/bin/python2.6 /path/to/venv/bin/python

or, better yet, recreate the virtualenv.

Booting ISO images from a USB drive

Dear lazyweb, I would like to download an arbitrary ISO image (say, a Ubuntu 10.04 Desktop CD) into a directory of a USB flash drive, and then make that USB flash drive boot that ISO image. I do not want to

  • re-partition or re-format the flash drive (this eliminates usb-creator, AFAIU)
  • extract the contents of the ISO image into the root of the USB drive (this eliminates unetbootin)
  • skip the ISO's bootloader and directly boot the kernel+initramfs from the ISO (eliminates this recipe, and this recipe)

I just want a bootloader on the USB to read the VFAT filesystem, mount the ISO image as a loop device, then chain-load the bootloader from that ISO. Bonus points for having a menu letting me choose one of several ISO images. Running a script to edit a text file (say, grub's config) to get that menu is fine.

Is this even possible? If not, can I at least have two out of three (no partition/extraction, but skipping intrinsic bootloader is fine)?

Solution that I finally chose (from Ubuntu forums):

Plug in USB key. Find out the mount point (/media/disk) and the device name (/dev/sdx) of the USB key with

$ mount|grep /media

Install GRUB 2 into the USB key with

$ sudo grub-install --root-directory=/media/usbdisk /dev/sdx

If it says something about embedding being impossible and falling back to UNRELIABLE blocklist-based setup, run

$ sudo grub-install --root-directory=/media/usbdisk /dev/sdx --force

Download a CD image, let's say ubuntu-10.10-desktop-i386.iso. Put it into /media/usbdisk/ubuntu/.

Create a text file /media/usbdisk/boot/grub/grub.cfg with

menuentry "Ubuntu 10.10 (x86 desktop livecd)" {
    set isofile="/ubuntu/ubuntu-10.10-desktop-i386.iso"
    loopback loop $isofile
    linux (loop)/casper/vmlinuz boot=casper iso-scan/filename=$isofile quiet splash noprompt --
    initrd (loop)/casper/initrd.lz
}

You can have as many ISO images as you want, just make sure to add a menuentry for each. There's no need to run grub-install again after adding or removing a .iso file. Oh, and if you want to use an ISO file for a different distribution, you'll have to figure out the correct linux and initrd lines somehow.

Update: Ubuntu 13.04 changed the name of the kernel -- use (loop)/casper/vmlinuz.efi instead of (loop)/casper/vmlinuz.

I tested it with the following images

  • ubuntu-10.04-desktop-i386.iso
  • ubuntu-10.04-server-i386.iso
  • ubuntu-10.04-server-amd64.iso
  • ubuntu-10.10-desktop-i386.iso
  • ubuntu-11.04-desktop-i386.iso
  • ubuntu-11.10-desktop-i386.iso
  • ubuntu-12.04-desktop-i386.iso
  • ubuntu-12.04-desktop-amd64.iso
  • ubuntu-12.04-server-i386.iso
  • ubuntu-12.04-server-amd64.iso
  • ubuntu-12.10-desktop-i386.iso
  • ubuntu-12.10-desktop-amd64.iso
  • ubuntu-13.04-desktop-amd64.iso

This solution skips the CD-ROM's boot menu. I haven't found a better one.

Update: I wrote a script to generate a grub.cfg for me so I don't have to do it by hand any more.

Re: Web frameworks considered useful.

Martijn Faassen defends web frameworks in a rather longish post (you can tell it's 5 AM in the morning and I've nearly defeated the unread post queue in Google Reader). I'd like to propose a condensed version. Consider this slogan:

Simple things should be easy; complicated things should be possible.

Frameworks make simple things easy. Good frameworks keep the complicated thing possible; poorly-designed frameworks make the complicated thing more difficult than necessary; bad frameworks make even simple things complicated.

Doing everything from scratch merely makes things possible, but rarely easy.