2011-08-06

How to set up nicely hinted default fonts on Linux

This blog post explains how to set up a per-user default font configuration under Linux (tested on Ubuntu Lucid), which contains easy-to-read fonts in small sizes and properly hinted rendering.

Install the Microsoft core fonts (e.g. Times New Roman, Arial, Courier New), using the following command (without the $ sign):

$ sudo apt-get install msttcorefonts

Create (or overwrite) the file ~/.fonts.conf with the following contents:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>

<!-- Accept bitmap fonts -->
  <selectfont>
    <acceptfont>
    <pattern>
      <patelt name="scalable"><bool>false</bool></patelt>
    </pattern>
    </acceptfont>
  </selectfont>

<!--  Enable proper hinting (medium) and disable subpixel rendering (rgba=none)
      for the Microsoft Core fonts (msttcorefonts) with high quality hints.
  --> 
  <match target="font">
    <test name="family"><string>Andale mono</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Arial</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Arial Black</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Comic Sans MS</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Courier New</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Georgia</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Impact</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Times New Roman</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Trebouchet MS</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Verdana</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>Webdings</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>

<!--  Just a safe bet: enable proper hinting for the DejaVu font family.
      Bitstream Vera is not shipped on Ubuntu Lucid anymore (but there was a
      package on Ubuntu Hardy).
  --> 
  <match target="font">
    <test name="family"><string>DejaVu Sans</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans Mono</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans,DejaVu Sans Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans,DejaVu Sans Light</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Sans Light</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Serif</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Serif,DejaVu Serif Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>
  <match target="font">
    <test name="family"><string>DejaVu Serif Condensed</string></test>
    <test name="pixelsize" compare="more"><double>7.5</double></test>
    <edit name="hinting"><bool>true</bool></edit>
    <edit name="hintstyle"><const>hintmedium</const></edit>
    <edit name="rgba"><const>none</const></edit>
  </match>

<!-- Set font family preferences for Firefox. Chrome seems to ignore these.
     Please note that /etc/fonts/conf.d/60-latin.conf has more defaults, which
     we don't have to repeat here.
  -->
  <alias><family>serif</family><prefer>
    <family>Times New Roman</family>
  </prefer></alias>
  <alias><family>sans-serif</family><prefer>
    <family>Arial</family>
  </prefer></alias>
  <alias><family>monospace</family><prefer>
    <family>DejaVu Sans Mono</family>
  </prefer></alias>
</fontconfig>

The hintmedium setting above is especially important, because it turns on the proper hinting for Times New Roman etc., which makes these fonts easy to read at small sizes. The default is slight hinting (instead of medium), which is wrong, and it remains wrong (because of a bug) even if you select it at System / Preferences / Appearance / Fonts / Details / Hinting / Medium. The proper way to get the medium hinting is to write a ~/.fonts.conf file, as above.

After changing ~/.fonts.conf log out and back in, or restart all applications for the changes to take effect.

Google Chrome doesn't pay attention to the default fonts specified in ~/.fonts.conf. In Chrome, visit chrome://settings/fonts, and change the defaults to:

  • Standard Font: Times New Roman
  • Serif Font: Times New Roman
  • Sans Serif Font: Arial
  • Fixed-Width Font: DejaVu Sans Mono

You may want to change the window title and dialog box fonts as well. You can do that in System / Preferences / Appearance / Fonts. See this blog post for some crisp (i.e. non-antialiased), small font size defaults. Don't forget to install the FixedSC and Helxetica fonts first, as documented there.

How to set up English search in Google Chrome

This blog post explains how to set up the default search engine to Google in English language in Google Chrome.

By default, if Google is the default search engine in Google Chrome, it returns the search result in the language of the country which is autodetected as the location of the computer. This is bad behavior for most English-speaking travelers, who always want the search results in English, no matter which country they are visiting.

To fix it for yourself, go to chrome://settings/searchEngines in Chrome, and add a new search engine named Google in English, the shortcut (second column) being gg , and the URL being http://www.google.com/search?hl=en&q=%s . Save it, make it the default, and remove all other search engines with Google in their name.

From now on, you can type a search query to the address bar (optionally prefixed by gg and a space), and you will get Google results in English.

Unfortunately the search engine setting is not synchronized between your Google Chrome installations, so you have to configure it manually on each machine and login account.

2011-08-04

How to disable cursor blinking in GNOME applications

This blog post explains how to make the cursor not blink in text input and text area widgets in GNOME applications (including GNOME Terminal). The settings have been tested and found working on Ubuntu Lucid.

Run the following commands (without the leading $) in a terminal window:

$ gconftool-2 --set /desktop/gnome/interface/cursor_blink --type boolean False
$ gconftool-2 --set /apps/gnome-terminal/profiles/Default/cursor_blink --type boolean False
$ gconftool-2 --set /apps/gnome-terminal/profiles/Default/cursor_blink_mode --type string off

Changes take effect immediately, there is no need to restart running applications.

These changes also affect Google Chrome (including the address bar and input fields and textarea fields on the page). However, changes don't take effect within a pages in existing tabs, so you should close them, and create new tabs.

If some cursors still Please see this noblink page to disable blinking in Emacs, XEmacs, GVIM, GTK, Gimp, Qt, LessTif, Mozilla Firefox, Mozilla Thunderbird, Google Chrome, TCL/Tk, Linux console and Microsoft Windows.

How to write hello-world in both Java and C++

This blog post explains hwo to write a hello-world program which compiles in both Java and C++.

The following solution makes use of the language difference that //...\ continues the one-line comment in C++, but not in Java.

//\
class t{public static void main(String[]a){System.out.print/*
#include<stdio.h>
int main(){if(1){return!printf//*/
("Hello, World!\n");}}

2011-06-24

Python 3.2 binaries released in StaticPython for Linux

This blog post is to announce that StaticPython, a binary distribution of Python, has just released Python 3.2 binaries for Linux. (Previously StaticPython contained only Python 2.7 binaries.) Download links for the binaries:

  • python3.2: almost all built-in Python modules, C extensions (including sqlite3) and greenlet
  • stackless3.2: ditto, but with Stackless Python
  • stacklessxl3.2: ditto, and also OpenSSL (with the _ssl and _hashlib modules)

The Python 3.2 binaries of StaticPython can be useful on Linux and FreeBSD systems where Python 3.2 distribution packages are not available, and recompiling from source would be too inconvenient. They can also be used to demo the features of Python 3 for users with a little time and patience, and without a commitment to install it.

2011-06-05

PTetriS/HTML: A minimalistic, but correct Tetris-clone in HTML + JavaScript

This blog post is to announce PTetriS/HTML, a minimalistic, but correct Tetris-clone in HTML + JavaScript. Play PTetriS/HTML here, with a JavaScript-enabled browser.

PTetris/HTML was born to celebrate the coming 10-year anniversary of PTetris, the same Tetris-clone implemented as a Java applet and application. Play PTetriS here, with a Java-enabled browser.

Please note that the PTetriS games are not feature rich (e.g. they don't count the score and they don't show the next brick, and they don't have multiple levels). This is intentional, so they can work as a reference implementation of a correct Tetris game. By correct I mean that the board size is correct, bricks rotate in the correct direction, and the rotation pixel pattern of the bricks is correct (e.g. they don't jump up or down when changing the rotation phase). These properties are copied from the old game FUXOFT's Tetris2 (architecture: ZX Spectrum). There are many Tetris-clones available nowadays which are incorrect.

2011-06-04

How to download a https:// page in Ruby 1.8

This blog post shows an example low-level implementation of downloading a https:// page in Ruby 1.8. The reason why is this blog post was born is that the documentation of the openssl and socket Ruby modules didn't contain a working end-to-end example.

#! /usr/bin/ruby1.8
require 'socket'
require 'openssl'
# Returns a HTTP response header + body.
def download_https(host, port, suburl)
  s = TCPSocket.new('www.gmail.com', 443)
  begin
    ss = OpenSSL::SSL::SSLSocket.new(s)
    begin
      ss.connect
      ss << "GET #{suburl} HTTP/1.0\r\nHost: #{host}:#{port}\r\n\r\n"
      ss.flush
      ss.read
    ensure
      ss.close
    end
  ensure
    s.close
  end
end
p download_https('www.gmail.com', 443, '/')

Please note that this doesn't check the authenticity of the server, i.e. it will happily and silently accept self-signed certificates.

2011-05-19

jtty-builder: easy-to-install JSP web server for Unix

This blog post is an announcement for jtty-builder, an easy-to-install, lightweight webserver with a JSP container for Unix. More specifically, jtty-builder is just a set of shell scripts for Unix which automate downloading and building a lightweight Java web and application server for serving JSP (and Java servlets). The container used is Jtty, which uses Jetty, which uses parts of Apache Tomcat (mostly Jasper). Most steps are automated. There is no need to write configuration files.

See the most recent documentation of jtty-builder here.

To start serving a hello-world JSP page on Unix, do this:

  1. As a shortcut, you can use a prebuilt jttyp.jar instead of building one using jtty-builder. To do that, run the following command, and skip steps 1 to 5 (inclusive):
    $ wget -O jttyp.jar \
        http://pts-mini-gpl.googlecode.com/svn/trunk/jtty-prebuilt/jttyp.jar
  2. Download jtty-builder:
    $ svn co http://pts-mini-gpl.googlecode.com/svn/trunk/jtty-builder
  3. Install java and javac. Example command on Ubuntu Lucid:
    $ sudo apt-get install openjdk-6-jdk
  4. Use jtty-builder to download the sources of Jtty, Jetty and Tomcat:
    (cd jtty-builder && ./download_jttyp.jar)
  5. Use jtty-builder to build jttyp.jar:
    $ (cd jtty-builder && ./build_jttyp.jar)
  6. Copy jttyp.jar to the application directory:
    $ cp jtty-builder/jttyp.jar .
  7. Create your .war file or application directory. A simple example:
    $ mkdir Hello-World
    $ (echo '<html><head><title>JSP Test</title>'
       echo '<%! String message = "Hello, World."; %>'
       echo '</head><body><h2><%= message %></h2>'
       echo '<%= new java.util.Date() %></body></html>') >Hello-World/hi.jsp
    $ mkdir Hello-World/WEB-INF
    $ (echo '<web-app>'
       echo '<display-name>Hello World</display-name>'
       echo '</web-app>') >Hello-World/WEB-INF/web.xml
  8. Start the Java application server running your Hello-World application:
    java -jar jttyp.jar 8765 Hello-World

    (Keep the java application running.)

  9. Try the web page in your web browser by visiting http://127.0.0.1:8765/ Reload it to get the time updated.

    If you modify hi.jsp and reload the page, it gets autmatically recompiled and the new version will run.

See the Jtty project page for more information about using jtty.jar and jttyp.jar for staring Java web applications from the command line.

2011-04-27

How to write a simple echo and chat server in Ruby 1.8

This blog post is an introduction to TCP socket server programming and thread programming in Ruby 1.8. It also illustrates how compact and expressive Ruby code can be. The intended audience is Ruby beginners.

require 'socket'  # TCPServer
ss = TCPServer.new(1233)
loop {
  Thread.start(ss.accept) { |s|
    begin
      while line = s.gets;  # Returns nil on EOF.
        (s << "You wrote: #{line.inspect}\r\n").flush
      end
    rescue
      bt = $!.backtrace * "\n  "
      ($stderr << "error: #{$!.inspect}\n  #{bt}\n").flush
    ensure
      s.close
    end
  }
}

Use telnet 127.0.0.1 1233 to connect to the echo server as a new participant, and then type your chat message(s) terminated by Enter (newline). The echo server sends back each message it receives with the You wrote boilerplate around it. Multiple independent clients can connect to the chat server at a time.

The chat server:

require 'socket'  # TCPServer
require 'thread'  # Queue
ssock = TCPServer.new(1234)
msgs = Queue.new
participants = []
Thread.start {  # Send chat messages to participants.
  while msg = msgs.pop;  # Always true.
    participants.each { |s|
      (s << msg).flush rescue IOError
    }
  end
}
loop {
  Thread.start(ssock.accept) { |sock|
    participants << sock
    begin
      while line = sock.gets;  # Returns nil on EOF.
        msgs << ": #{line.chomp!}\r\n"
      end
    rescue
      bt = $!.backtrace * "\n  "
      ($stderr << "error: #{$!.inspect}\n  #{bt}\n").flush
    ensure
      participants.delete sock
      sock.close
    end
  }
}

Use telnet 127.0.0.1 1234 to connect to the chat server as a new participant, and then type your chat message(s) terminated by Enter (newline). The chat server sends each message (with a colon prepended) to all connected participants.

The Ruby source files above demonstrate the following:

  • how to create a thread
  • how to use thread-local variables (e.g. sock)
  • how to report exceptions in a thread
  • how to ignore IOError
  • how to read a line from a socket
  • how to use the Queue class for synchronization between threads
  • how to clean up using an ensure block
  • how to pass values to a newly created thread

2011-04-09

python-xattr-compat: portable Python module to query and set POSIX extended attributes of files

This blog post is an announcement of python-xattr-compat, a portable Python 2.x module to query and set POSIX extended attributes of files.

python-xattr-compat is a wrapper around the xattr Python package, but if xattr is not available, python-xattr-compat provides compatible replacement implementations (using the dl or ctypes modules) for some systems (currently Linux), so we have a pure Python implementation for extended attribute manipulations.

How it works: Many scripting languages have a syscall function to call arbitrary system calls (like lsetxattr(2)). Python doesn't have syscall built in, but it has the dl and ctypes modules, which let the programmer call functions in any C library, lincluding libc. Since libc on Linux has wrappers for syscall and lsetxattr etc., we can call these to get system-specific extended attribute manipulation without installing non-built-in Python extensions like xattr.

2011-04-03

How to install CyanogenMod onto the ZTE Blade

This blog post explains how I managed to install CyanogenMod to a ZTE Blade phone (both Gen 1 and Gen 2). Please note that there can be multiple solutions, some of them working only on some phone submodels. The solution I give here did work on the model I had.

Pick one of the methods below.

Method one: without rooting the phone (recommended)

This method is recommended, because it is the more straightforward and safer method. Although its description is longer than of method two, doing method one is faster.

You will need a USB cable to connect the phone to a computer and an SD card in the phone.

Instructions:

  1. Make a backup of your data on the phone, this page has some suggestions how (don't use Titanium Backup though, because that needs a rooted phone). You may safely skip this step if you don't have any SMS, phone call log entry, application data, application configuration etc. to save (e.g. because the phone is new and you haven't customized it yet).
  2. Make sure you know your wifi connection credentials (e.g. network name, security type, passphrase).
  3. Make sure you know your Google account name (e-mail address) and password.
  4. On the phone: Settings » Applications » Development » enable USB Debugging.
  5. On the phone: Settings » Applications » enable Unknown sources – Allow installation of non-Market applications
  6. Install the Ask Mr Pigfish application from the Market, run Ask Mr Pigfish, and see it displaying the generation number of your phone (gen1 or gen2). Take a not on paper containing the generation number.
  7. Install the adb and the fastboot tools to your computer. For Linux, see How to install instructions below. For Windows or Mac, see this page. Another download for fastboot is on this page.
  8. The command lines in following instructions are for Linux. Do it similarly on Mac and Windows (e.g. instead of wget, use your browser or download manager to download the file).
  9. Download the ClockworkMod recovery with wget -O /tmp/recovery-clockwork-3.0.1.4-blade.img http://android.d3xt3r01.tk/cyanogen/blade/recovery/recovery-clockwork-3.0.1.4-blade.img
  10. Download the latest version of CyanogenMod from this page. When these instructions were written, the equivalent download command was: wget -O /tmp/update-cm-7.0.0-RC4-Blade-signed.zip http://mirror.cyanogenmod.com/get/update-cm-7.0.0-RC4-Blade-signed.zip
  11. Download the latest version of Google Apps from this page. When these instructions were written, the equivalent download command was: wget -O /tmp/gapps-gb-20110307-signed.zip http://android.d3xt3r01.tk/cyanogen/gapps/gapps-gb-20110307-signed.zip
  12. If already connected, disconnect the phone from the computer.
  13. Remove the SIM card from the phone if you don't have a data plan. This is to prevent the unconfigured CyanogenMod from making expensive data transfers before the wifi is configured. This needs powering off your phone first.
  14. Power the phone back on and wait for it to start up.
  15. Connect the phone to the computer using the USB cable. The phone should display a notification that an USB cable is connected (and possibly another notification that USB debugging is enabled).
  16. Run adb devices on the computer, it should display something like
    List of devices attached 
    Blade-CM7       device
  17. Copy the CyanogenMod ZIP file to the SD card by running adb push /tmp/update-cm-7.0.0-RC4-Blade-signed.zip /sdcard/cm.zip
  18. Copy the Google Apps ZIP file to the SD card by running adb push /tmp/gapps-gb-20110307-signed.zip /sdcard/gapps.zip
  19. To prevent data loss below, make sure the phone is fully charged. You can charge it quickly if you connect it to a wall socket instead of a computer.
  20. If you have a gen1 phone and you want to install CyanogenMod 7.0.1 or later, then upgrade your phone to gen2 by following the How to upgrade a gen1 phone to gen2 and start ClockworkMod recovery below. Otherwise, follow these instructions:
    1. Reboot the phone to fastboot mode by running adb reboot bootloader
    2. Wait for about 20 seconds until the phone reboots into bootloader mode, showing only the green android logo on the screen. (If your phone boots normally a few seconds later, then this method has failed for you, please choose another method to install CyanogenMod to your phone. You may try removing the battery, reinserting the battery, holding the Volume Up key on the phone, and powering on the phone while Volume Up is still held.)
    3. Run fastboot flash recovery /tmp/recovery-clockwork-3.0.1.4-blade.img
    4. Run fastboot reboot
    5. Wait for the phone to start up and detect that the USB cable is connected.
    6. Run adb reboot recovery (this should take about 5 seconds).
    7. Wait for about 5 seconds until the phone reboots into recovery mode, running the ClockworkMod recovery.
  21. Your phone should be running ClockworkMod recovery now. It should display ClockworkMod Recovery v3.0.1.4 (or a larger version number) and a menu below, starting with reboot system now. Use the Volume Up and Volume Down keys to navigate the menu up or down. Navigate to the advanced item, use the Home button to select it. Use the Back button to go back to the main menu.
  22. Select the main menu option Wipe data/factory reset
  23. Select the main menu option Wipe cache partition
  24. Select the main menu option Install zip from sdcard
  25. Select the menu option Choose zip from sdcard
  26. Select cm.zip . This will install CyanogenMod.
  27. Go back to the main menu. Select the main menu option Install zip from sdcard
  28. Select the menu option Choose zip from sdcard
  29. Select gapps.zip . This will install Google Apps.
  30. Go back to the main menu.
  31. Select the main menu option reboot system now
  32. CyanogenMod should be booting now. Configure everything for your needs.
  33. Use the Menu button to configure the wifi first (i.e. below you enter your Google account password).
  34. CyanogenMod might ask you which Google applications to install. If unsure, select all of them. After you make your selection, CyanogenMod will take you the Market page of all these applications. Accept and install them one by one.
  35. If you don't have a data plan, make sure you configure the phone so it won't accidentally make data transfers.
  36. Reinsert the SIM card. This needs powering off your phone first.

How to install adb and fastboot on Linux

# You might need to use anoter package manager for installation:
$ sudo apt-get install wget unzip
$ wget -O /tmp/linux_adb_fastboot.zip \
  http://android.d3xt3r01.tk/cyanogen/tools/linux_adb_fastboot.zip
$ (cd /usr/local/bin && sudo unzip /tmp/linux_adb_fastboot.zip)
$ sudo killall -9 adb
# This starts the daemon. `sudo' is not necessary on some systems.
$ sudo /usr/local/bin/adb devices

How to upgrade a gen1 phone to gen2 and start ClockworkMod recovery

Don't follow these steps unless you are asked to by another step in this howto.

Please note that these instructions apply only to gen1 (1st generation) ZTE Blade models. Doing it on any other phone (i.e. on a gen2 ZTE Blade or any phone other than a ZTE Blade) will most probably make the device useless beyond repair. You can use the Ask Mr Pigfish application (available from the Android Market) to check if you have a gen1 ZTE Blade.

Please note that by following these instructions, not only the configuration and user data, but the operating system will also be removed from the phone. (But the contents of the SD card will remain intact.) To make your (gen2) device useful after these instructions, you should already have an operating system installer ZIP file (e.g. cm.zip above) already on the SD card.

Instructions:

  1. Download the ZIP file Gen1-to-Gen2-TPT-v2.zip from here. The download link can also be found in the section Update to Gen2 Radio of this page.
  2. Unzip the contents of the ZIP file to the SD card, so there should be a folder named image in the root folder of the SD card, and that folder should contain 17 files, from amss.mbn to userdata.img . Make sure that the image folder is in the root folder of the SD card. The easiest way to do this is connecting your phone to the computer using the USB cable, mounting the SD card (using the notification area of the phone), and running a ZIP file extractor on the computer. Disconnect the drive from the computer, and umount the SD card when done.
  3. Make sure the phone is fully charged.
  4. Disconnect the phone from the computer and the charger.
  5. Turn off the phone (by long pressing the power button).
  6. Remove the battery.
  7. Reinsert the battery.
  8. Hold the volume up and menu buttons. Don't release them yet.
  9. (Before doing this, read the next instruction step.) Push the power button to turn the phone on.
  10. Text in green would start appearing on a black background. Release the volume up and menu buttons.
  11. More text in green would start appearing with some indication of progress percentage. Wait for 30 seconds until its done.
  12. The phone boots to ClockworkMod Recovery .

Method two: rooting the phone first

You will need an SD card in the phone.

Outline (see the detailed instructions in the links below):

  1. Make a backup of your data on the phone. (See in method two below.)
  2. Make sure you know your wifi connection credentials (e.g. network name, security type, passphrase).
  3. Make sure you know your Google account name (e-mail address) and password.
  4. Root the phone.
  5. Install the ROM Manager application (from the Android Market).
  6. Install ClockworkMod recovery using the ROM Manager application. (This step needs a rooted phone.)
  7. Download the CyanogenMod update ZIP file (and possibly the Google Apps ZIP file) to the /sdcard.
  8. To prevent data loss below, make sure the phone is fully charged. You can charge it quickly if you connect it to a wall socket instead of a computer.
  9. Remove the SIM card from the phone if you don't have a data plan. This is to prevent the unconfigured CyanogenMod from making expensive data transfers before the wifi is configured. This needs powering off your phone first.
  10. Use the ROM Manager application to start the ClockworkMod recovery.
  11. Within ClockworkMod recovery, wipe the phone.
  12. Within ClockworkMod recovery, install the CyanogenMod update ZIP file (and possibly the Google Apps ZIP file)
  13. Within ClockworkMod recovery, reboot the phone.
  14. CyanogenMod should be booting now. Configure everything for your needs.
  15. If you don't have a data plan, make sure you configure the phone so it won't accidentally make data transfers.
  16. Reinsert the SIM card. This needs powering off your phone first.

All these steps worked for me as explained in detail on the official install CyagnogenMod to ZTE Blade page, except for rooting the phone. That page and also most other web sites instruct the user to reboot the fastboot mode by holding the Volume Up key while powering up the phone. This didn't work for me, because my ZTE Blade had fastboot disabled (so it always booted normally). So I had to find another way to root the phone. The instructions on this page (those containing tinyurl.com/urooted) worked for me. These instructions use a version of the Universal Androot application specialized to the ZTE Blade. Please note that Universal Androot claims that the phone is already rooted — just ignore this message and root it anyway. Please also note that during the installation process you have to re-root the phone using Universal Androot each time you reboot the phone. So if ROM Manager complains that your phone is not rooted, then just run Universal Androot again, and then retry in ROM Manager.

Performance

If the phone feels slow and games are not enjoyable, then tune the performance settings:

  1. Make sure that the latest version of CyanogenMod (at least 7.0.0 without RC in the version number) is installed. Get the newest version of the ZIP file from here. Copy the ZIP file to the (root of the) SD card. Reboot the phone to recovery mode (using adb reboot recovery or the ROM Manager application). In recovery mode, clear the cache and then select the update file (the ZIP file), install it, and reboot the phone.
  2. Make sure that Application / Settings / CyanogenMOD Settings / Performance / Enable surface dithering is off.
  3. In Application / Spare Parts make sure that all animations are disabled.
  4. There seems to be no need for enabling GPU acceleration (debug.sf.hw=1 in /system/build.prop), CyanogenMod seems to be fast without it.

2011-03-25

How to automatically synchronize the shell history between terminal windows

This blog post explains how to automatically synchronize the Unix shell command-line history between multiple shell instances running on the same computer (but possibly different terminal windows), without requiring any manual action (such as running history -w or exiting from the shell) from the user, and also how to make commands be saved to the history file right at the point when the command is executed. The solutions described here work with bash 4.1 (tested with 4.1.5) or newer and zsh (tested with 4.3.4 and 4.3.10), run on Ubuntu Lucid. No attempt was made to synchronize the zsh history and the bash history.

Instructions for zsh

Put (append) this command to your ~/.zshrc and reopen your terminal windows so that the changes take effect:

setopt hist_ignore_dups share_history inc_append_history extended_history

The change takes effect in terminal windows and incoming SSH connections you open from now on. Close your old windows if necessary to avoid confusion. You can also run the source ~/.zshrc to make the change take effect.

Optionally, set your HISTSIZE and SAVEHIST to large enough values, e.g. put HISTSIZE=500000 SAVEHIST=5000000 in your ~/.zshrc.

Once the change took effect, you can start running a command in one terminal window, then just press Enter in another terminal window, then press Up in the other terminal window to get the command running in the other terminal window. Your shell history lines are now synchronized. Synchronization happens whenever you press Enter in a terminal window.

Instructions for bash

Since bash doesn't have the history sharing feature by default, you need to use a helper script for bash. Download it using the following command (without the first $):

$ wget -O ~/merge_history.bash http://raw.github.com/pts/pts-merge-history-bash/master/merge_history.bash

Run

$ touch ~/.merged_bash_history

to signify to the helper script that you want to use the new history feature.

Put (append) this to your ~/.bashrc so the helper script gets loaded at shell startup:

source "$HOME"/merge_history.bash

Optionally, set HISTSIZE and HISTFILESIZE to large enough values, e.g. append the following to your ~/.bashrc:

HISTSIZE=500000 HISTFILESIZE=5000000

The change takes effect in terminal windows and incoming SSH connections you open from now on. Close your old windows if necessary to avoid confusion. You can also run the source command above to make the change take effect.

Once the change took effect, you can start running a command in one terminal window, then just press Enter in another terminal window, then press Up in the other terminal window to get the command running in the other terminal window. Your shell history lines are now synchronized. Synchronization happens whenever you press Enter in a terminal window.

If you want your old shell history to be reused, please copy it any time, and then press Enter:

cp ~/.bash_history ~/.merged_bash_history

Explanation of the bash solution

Bash doesn't have support for manual or automatic synchronization of history files. By default, bash reads the history file ~/.bash_history (can be changed by setting the HISTFILE bash special variable) at startup, adds newly executed commands to its in-memory history buffer, and simply writes (or appends) the contents of the buffer to the history file upon clean exit. With this strategy, commands can be lost for good if the shell is killed with kill -9, or multiple shells are exiting (the last one wins, lines from all previous ones get irrecoverably lost). It's possible to affect this behavior with shopt -s histappend to force appending instead of overwriting, but that's still much less synchronization with command sorting by timestamp. The commands history -w, history -a history -c and history -r can be useful for managing the bash history files, but they may still cause data loss (see above).

To solve these problems, the helper script merge_history.bash above uses the following techniques:

  • It uses HISTTIMEFORMAT bash special variable to make sure timestamps are saved into the history file.
  • It contains a Perl script to merge history files (possibly created by concurrently running bash instances), sorting the results by timestamp and removing duplicates.
  • Before displaying the prompt (using the PROMPT_COMMAND bash special variable) loads the merged history file from disk.
  • When the user presses Enter to run a command, before the command is executed, it saves the in-memory history buffer to a file, and merges that file using the Perl script to the merged history file. It uses trap ... DEBUG (and various black magic trickery) to install its hook before the command is executed. Other solutions for bash history synchronization don't use this technique, so they suffer from the shortcoming of saving the most recently executed command too late (only when it finishes).
merge_history.bash was inspired by the bash preexec emulation script.

Get the most recent version of merge_history.bash from http://raw.github.com/pts/pts-merge-history-bash/master/merge_history.bash . For your studying convenience, here is an outdated copy:

MRG_DONEI=":$SHELLOPTS:"
if test "${MRG_DONEI#*:history:}" != "$PTS_DONEI" &&
   (test "${BASH_VERSION#[5-9].}" != "$BASH_VERSION" ||
    test "${BASH_VERSION#4.[1-9].}" != "$BASH_VERSION") &&
   test "$HOME" &&
   test -f "$HOME/.merged_bash_history"; then

# Merge the timestamped .bash_history files specified in $@ , remove
# duplicates, print the results to stdout.
function _mrg_merge_ts_history() {
  PERL_BADLANG=x perl -wne '
    use integer;
    use strict;
    use vars qw($prefix @lines);
    if (/^#(\d+)\n/) {
      $prefix = sprintf("%030d ", $1);
    } else {
      chomp; $prefix = sprintf("%030d ", time) if !defined $prefix;
      push @lines, "$prefix$_\n"; undef $prefix;
    }
    END {
      my $prev = "";
      for (sort @lines) {
        s@^(\d+) @@; my $ts = $1 + 0; my $cur = "#$ts\n$_";
        print $cur if $cur ne $prev;
        $prev = $cur;
      }
    }
  ' -- "$@"
}

# Read history from $HISTFILE_MRG, 
function _rdh() {
  test "$HISTFILE_MRG" || return
  local HISTFILE="$HISTFILE_MRG"
  # Make `history -w' prefix "$TIMESTAMP\n" to $HISTFILE
  local HISTTIMEFORMAT=' '
  history -c  # Clear the in-memory history.
  history -r  # Append the contents of $HISTFILE to the in-memory history.
}

export -n HISTTIMEFORMAT HISTFILE HISTFILE_MRG
unset HISTFILE  # No history file by default, equivalent to HISTFILE="".
unset HISTTIMEFORMAT
HISTFILE_MRG="$HOME/.merged_bash_history"
history -c  # Discard the current history, whatever it was.

function hook_at_debug() {
  test "$COMP_LINE" && return  # Within the completer.
  trap '' DEBUG  # Uninstall debug trap.
  test "$HISTFILE_MRG" || return
  if : >>"$HISTFILE_MRG"; then
    # Make `history -w' prefix "$TIMESTAMP\n" to $HISTFILE
    local HISTTIMEFORMAT=' '
    # TODO(pts): Don't save if nothing changed (i.e. `history -1` prints
    # the same sequence number as before).
    local TMPDIR="${TMPDIR:-/tmp}"
    local HISTFILE="$TMPDIR/whistory.$UID.$$"
    local MHISTFILE="$TMPDIR/mhistory.$UID.$$"
    history -w  # Write to /tmp/whistory.$$ .
    _mrg_merge_ts_history "$HISTFILE_MRG" "$HISTFILE" >"$MHISTFILE"
    command mv -f -- "$MHISTFILE" "$HISTFILE_MRG"
  fi
}

# Set these both so hook_at_debug gets called in a subshell.
set -o functrace > /dev/null 2>&1
shopt -s extdebug > /dev/null 2>&1

# As a side effect, we install our own debug hook. We wouldn't have to do
# that if bash had support for `preexec' (executed just after a command has
# been read and is about to be executed). in zsh.
PROMPT_COMMAND="trap '' DEBUG; _rdh; trap hook_at_debug DEBUG; $PROMPT_COMMAND"

fi  # End of the file's if guard.
unset MRG_DONEI

2011-02-16

How to dump the full /etc/passwd and /etc/group files when NIS (YP) or LDAP is used

This blog post explains how to dump the flattened version of /etc/passwd and /etc/group files on a Unix system when some user and group entries are stored in a NIS (YP), LDAP or other server.

To dump these fules, run the following commands (not as root, without the leading $).

$ getent group  >/tmp/group
$ getent passwd >/tmp/passwd

The equivalent commands in Perl (use them if getent(1) doesn't work for you):

$ perl -le'$,=":";while(@_=getgrent){$_[3]=~y@ @,@;print@_}'  >/tmp/group
$ perl -le'$,=":";while(@_=getpwent){print@_[0,1,2,3,6,7,8]}' >/tmp/passwd

For NIS (YP) users and groups only, one can use ypcat passwd and ypcat group, respectively.

2011-02-01

How to run Syncless on Linux without installing it?

This blog post explains how to run asynchronous, coroutine-based client and server I/O libraries like Syncless, gevent and Concurrence on Linux without installing them.

On Linux, it's possible to try Syncless without installation, using the StaticPython binary Python distribution, like this:

$ wget -O stacklessco2.7-static \
  https://raw.githubusercontent.com/pts/staticpython/master/release/stacklessco2.7-static
$ chmod +x stacklessco2.7-static
$ ./stacklessco2.7-static
Python 2.7.1 Stackless 3.1b3 060516 (release27-maint, Feb  1 2011, 16:57:16)
[GCC 4.1.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from syncless import coio
>>> coio.sleep(1.5)
(sleeping for 1.5 second)
<object object at 0xf7709490>
>>>

Limitations:

  • This solution requires Linux on x86 (i386) or x86_64 (amd64) architecture. If you have a different Unix system, you have to install Syncless the regular way (e.g. with sudo easy_install syncless).
  • This solution doesn't give you the newest version of Syncless.
  • You can't use Python extensions written in C, except for those compiled into stacklessco2.7-static. See the full list on the StaticPython home page.

Please note that StaticPython can run many other I/O frameworks and libraries, which don't require compiling C extensions. Such libraries include Eventlet, Tornado, Twisted, asyncore and circuits.

2011-01-21

How to implement the C printf function in C++ in a typesafe way?

This blog post explains how to implement the C printf() function in C++ in a typesafe and convenient way.

The most important advantage of the ANSI standard C printf() function are its compactness and expressive power. For example: printf("The %s answer is %05d.\n", "best", 42); means: take the next argument, treat it as a null-terminated string (const char*), and insert it. The format specifier %05d means: take the next argument as a signed integer, pad it with leading zeros to at least 5 digits, and insert it. Please note that printf() is not typesafe: the format specifier has to match the type of the argument. For example, %d wouldn't work for a long long (but %lld would be needed), and %d or %s wouldn't work for a double (but %g would be needed, and %Lg would be needed for a long double). On a mismatch, some compilers would indicate a compile error, others would generate misbehaving (i.e. with undefined behavior) code.

There is no equally expressive message formatting functionality in C++ with a similarly compact syntax. Of course, printf() as it is can be used in C++, but it isn't integrated conveniently with the C++ standard library: e.g. it's not possible to insert an std::string, it's not possible to write to an std::ostream, and it's not possible to append to an existing std::string. C++ streams (e.g. cout << "The " << "best" << " answer is " << 42 << ".\n";) bring type safety (e.g. no matter which integer, floating point or string type 42 and other arguments have, they will be inserted properly), but they don't provide compact and powerful formatting capabilities (e.g. how to specify to pad 42 with zeros to at lest 5 digits).

Would it be possible to combine the compactness and expressive power of printf() with the typesafe behavior of C++ streams? It isn't too hard to create a class named Print and implement an overloaded operator<< so that Print("The %s answer is %05d.\n") << "best" << 42 would work in a typesafe way (raising a run-time error reliably if the type of the argument doesn't match the format specifier, and converting the the size and type of the argument if needed, e.g. %d would work for both int and long long). But is it possible to do it while keeping the original syntax, like this: Printf("The %s answer is %05d.\n", "best", 42);?

Yes, that's possible, using two tricks: overloading operator, (the comma operator), and using a GCC feature of macro expansion with any number of arguments. The macro Printf would expand so that Printf("The %s answer is %05d.\n", "best", 42); expands to (C("The %s answer is %05d.\n"), "best", 42);, which is equivalent to operator,(operator,(C("The %s answer is %05d.\n", "best"), 42);. Here C is a helper class, who has a constructor C(const char* fmt) for the format string, and the relevant const C& operator,(const C&, const char*) and const C& operator,(const C&, int) comma operators are overloaded to do the actual printing, consuming a few more characters in the meantime from the format string, and using that format specifier to format the argument. Type safety is provided by the built-in overloading features of the C++ language (i.e. a different operator, is called based on the type of the argument).

One more trick is needed to get an compile-time error when printing of values of unsupported type is attempted, e.g. class Bad {}; Printf("%s", Bad());. By default, since there is no operator, overridden for the class Bad, the default comma operator is used silently, which is quite useless (compute the first argument, discard it, compute the second argument, return it), and effectively prevents the rest of the arguments from being printed. The solution here is to define template<typename T>void operator,(const C&, T t) { ... }, which would match all types (which are not matched by the non-template version of operator,), and if we write ... so that it produces a type error, then the problem is solved.

The source code of such a typesafe printf() implementation for C++ is available at http://code.google.com/p/pts-mini-gpl/source/browse/#svn/trunk/pts-printf. For the convenience of the programmer, it implements all these:

int Printf(const char* fmt, ...);  // To stdout.
int Printf(FILE*, const char* fmt, ...);
int Printf(std::ostream&, const char* fmt, ...);
int Printf(std::ostringstream&, const char* fmt, ...);
int Printf(std::ofstream&, const char* fmt, ...);
int Printf(std::string*, const char* fmt, ...);  // Append to string.
std::string SPrintf(const char* fmt, ...);

Please note that the implementation is not optimized for speed. Most probably it's not possible to implement a typesafe version of printf() which is also as fast.

2011-01-06

How to drop caches on Linux?

This blog post explains how to drop in-memory cache of data on disk (pagecache, dentries, inodes) on Linux. Dropping the cache is useful if one wants to run filesystem benchmarks in a reproducible way.

To drop the caches, run

$ echo 3 | sudo tee /proc/sys/vm/drop_caches

The solution above is from http://www.kernel.org/doc/Documentation/sysctl/vm.txt. Some other useful commands mentioned there:

$ echo 1 | sudo tee /proc/sys/vm/drop_caches  # drop pagecache
$ echo 2 | sudo tee /proc/sys/vm/drop_caches  # drop dentries and inodes
$ echo 3 | sudo tee /proc/sys/vm/drop_caches  # drop pagecache, dentries and inodes
Note: As this is a non-destructive operation and dirty objects are not freeable, the user should run sync first.

2011-01-05

Announcement from the Unix kitchen staff

A restaurant called fork() has recently been opened in our office building. The name was suggested and chosen by engineers. I imagine what kind of e-mail announcements they would be sending if the kitchen was run by Unix engineers.

fork() will be close()d this week, but it will not be shutdown(), we'll open() it again, but you have to wait() a couple of days. In the meantime, our hard-working and prof()essional kitchen staff is not idle(): they are learning new Asian recipes. Please read() the signs before coming to check if fork() is open(). We hope you'll have a great time() eating Peking duck, a broad select()ion of sandwiches, and ricEAGAIN with nice(), un-break()able chopsticks, 5 times() a week. We have installed a new smoke extinguisher, which is splice()d to the oven, so it won't signal() the fire alarm() anymore unnecessarily. If you have feedback, please write() to us. Or fill our poll() from (see the new link() on the home page) to help us keep in sync() with the employees' taste. Your creat()ive ideas are also welcome to improve the furniture decoration – it can also be a clone() of a restaurant in popular culture, with some geek flavor added. Please note you don't have access() to the building from the exit() on the 3rd floor, so enter at the reception, but lock() your bike first outside, to one of the pipe()s. There is no need to pause() in break() 3 for coffee, there is a grinder in fork() now.

**environ-mentalist disclaimer: No silkworms were kill()ed for the outfit of our cooks.

2010-12-19

How to write a C++ program without libstdc++

This blog post explains how to write a C++ program and compile with GCC (g++) so that the resulting binary doesn't depend on libstdc++. The reason for avoiding libstdc++ can be purity (don't depend on libraries you don't really need) and statically linking small tools (e.g. for Unix or Win32 console applications with MinGW).

The limitations are:

  • The standard C++ STL (e.g. #include <string> and #include <vector>) cannot be used. This functionality has to be reimplemented in the program.
  • The standard C++ streams (e.g. #include <iostream>) cannot be used. The standard C I/O library (e.g. #include <stdio.h>) is a smaller and faster replacement. A disadvantage: there is no polymorphic operator<<(ostream&, ...) method for convenient, type-agnostic output.
  • Exceptions cannot be used (i.e. try, catch and throw are disallowed).
  • RTTI (run-time type information) cannot be used.
  • dynamic_cast<...>(...) cannot be used (because it requires RTTI).

Here is how to do it:

  • Add the following C++ code to your program (can be in a separate source file):
    #include <stdlib.h>
    #include <unistd.h>  /* for write(), also available on Windows */
    extern "C" void* emulate_cc_new(unsigned len) { \
      void *p = malloc(len);
      if (p == 0) {
        /* Don't use stdio (e.g. fputs), because that may want to allocate more
         * memory.
         */
        (void)!write(2, "out of memory\n", 14);
        abort();
      }
      return p;
    }
    extern "C" void emulate_cc_delete(void* p) {
      if (p != 0)
        free(p);
    }
    void* operator new  (unsigned len) __attribute__((alias("emulate_cc_new")));
    void* operator new[](unsigned len) __attribute__((alias("emulate_cc_new")));   
    void  operator delete  (void* p)   __attribute__((alias("emulate_cc_delete")));
    void  operator delete[](void* p)   __attribute__((alias("emulate_cc_delete")));
    void* __cxa_pure_virtual = 0;
  • Compile your program with g++ -c to create individual .o files. Add flags -fno-rtti -fno-exceptions to get compile errors for disabled features (exceptions and RTTI).
  • Link your executable with gcc -o prog code1.o code2.o ... It's important that you use gcc here instead of g++ because g++ would link against libstdc++.

This method has been tested and found working with GCC 3.2, GCC 4.2.1 and GCC 4.4.1 (both native Linux compilation and MinGW compilation), and it probably works with other GCC versions as well.

If you need dynamic_cast, add void* __gxx_personality_v0 = 0;, don't use -fno-rtti, and add dyncast.a to the gcc -o ... command-line. Here is how to create dyncast.a (about 55kB) for GCC 4.4.1:

$ ar x /usr/lib/gcc/i486-linux-gnu/4.4/libstdc++.a \
  dyncast.o class_type_info.o si_class_type_info.o pointer_type_info.o \
  pbase_type_info.o tinfo.o fundamental_type_info.o
$ ar crs dyncast.a \
  dyncast.o class_type_info.o si_class_type_info.o pointer_type_info.o \
  pbase_type_info.o tinfo.o fundamental_type_info.o

How to boot GRUB from SysLinux

This blog post explains how to boot GRUB from SysLinux. Only GRUB1 is covered, the solution explained doesn't support GRUB2.

Older versions of SysLinux (such as 3.83) don't support booting GRUB, i.e. they cannot load and boot the stage2 file of GRUB. The newest version of SysLinux contains chain.c32, which can boot many operating systems and bootloaders, including GRUB. The solution explained here doesn't use this feature, so it works with old versions of SysLinux as well.

The fundamental idea is to convert the GRUB stage2 file to a format which SysLinux can boot directly. This format is bzimage, the big variant of the Linux kernel image. grub.exe, part of GRUB4DOS is already in this format, so adding the following lines to syslinux.cfg works:

label grub4dos
menu label GRUB4DOS
kernel grub.exe

However, one might wish to use the original GRUB instead, because GRUB4DOS has some features missing, e.g. it doesn't support GPT (GUID Partition Table) and UUID on reisrefs partitions. Converting the original GRUB stage2 file to bzimage format is easy: just append it to the first 20480 bytes of grub.exe. SysLinux can boot this hybrid, but then GRUB wouldn't be able to find its configfile (menu.lst). To fix that, the full pathname of the configuration file has to be embedded to the boot image. The Perl script grub2bzimage.pl automates this.

grub2bzimage is a Perl script which converts the GRUB bootloader code (stage2) to bzimage format, which can be booted directly by SysLinux and other bootloaders. grub2bzimage.pl doesn't support GRUB2.

Example use to create grubzimg:

$ perl ./grub2bzimage.pl stage2 grubzimg '(hd0,0)/boot/grub/menu.lst'
Write this into syslinux.cfg:
label grub
menu label GRUB
kernel grubzimg

Please note that it's not possible to specify the name of the configfile (menu.lst) in syslinux.cfg (using append). The configfile has to be specified when grubzimg is created.

grub2bzimage.pl has been tested with SysLinux 3.83. Please note that newer versions of SysLinux contain chain.c32 which supports loading GRUB stage2 files directly.

2010-12-14

How to get multiple clickable desktop notifications on Ubuntu Lucid

This blog post explains how to get multiple clickable desktop notifications (i.e. those that were present on Ubuntu Hardy) on the default GNOME desktop of Ubuntu Lucid.

Desktop notifications are short messages displayed by programs for a short time in one of the corners of the screen. In Ubuntu Lucid, by default, they are displayed in the top right corner, their background is black, they are not clickable (i.e. it's not possible to click them away), they disappear while the mouse is over them, and at least 1 of them is visible at the same time. In Ubuntu Hardy, they are displayed in the bottom right corner of the screen, their background is similar to light grey, they are clickable (i.e. they disappear for good if the user clicks on them), they don't disappear while the mouse is over them, and if more than one of them can be on screen without overlap.

Ubuntu Lucid uses the notify-osd backend for displaying notifications. It's not possible to configure the notify-osd backend to make it work like Ubuntu Hardy. However, it's possible to install notification-daemon, which was the default backend in Ubuntu Hardy to for displaying notifications. Here is how to make it work in Ubuntu Lucid:

$ sudo apt-get install notification-daemon
$ sudo perl -pi -e 's@^Exec=.*@Exec=/usr/lib/notification-daemon/notification-daemon@' /usr/share/dbus-1/services/org.freedesktop.Notifications.service
$ sudo killall notify-osd

Try it with:

$ notify-send foo; notify-send bar

Optional change to disable notify-osd completely: (It may screw up volume notifications etc., so don't use it unless it doesn't work without it.)

$ sudo rm -f /usr/share/dbus-1/services/org.freedesktop.Notifications.service.*

See this discussion with some links for other notify-osd improvements and alternatives.

2010-12-11

A dramatic colored picture of a tiger's head

This blog post documents my unsuccessful software archeology attempt to find the origin and the author of the famous PostScript tiger colorful vector graphics. Get the (mostly unchanged) EPS file from the Ghostscript SVN repository, here.

The earliest Ghostscript version containing the tiger I could dig up is version 2.6.1 (5/28/93) [download] in Slackware Linux 1.1.2. FYI The earliest Ghostscript version in Debian is 2.6.1 as well [download].

The image itself contains the comment %%CreationDate: 4/12/90 3:20 AM, so the earliest possible Ghostscript version that can contain it is 2.0 (released on 9/12/90) — but I wasn't able to find a download link for that Ghostscript. The author and the copyright is not indicated. The only description is found in the Ghostscript history.doc file, saying tiger.ps - A dramatic colored picture of a tiger's head.

Even Wikipedia doesn't specify the origin of the tiger graphics. All I could find is this question asking where it comes from.

Here is the relevant part of the EPS header in the tiger.ps and tiger.eps file:

%%Creator: Adobe Illustrator(TM) 1.2d4
%%For: OpenWindows Version 2
%%Title: tiger.eps
%%CreationDate: 4/12/90 3:20 AM
%%DocumentProcSets: Adobe_Illustrator_1.2d1 0 0
%%DocumentSuppliedProcSets: Adobe_Illustrator_1.2d1 0 0

What I've learned: Linux distributions (especially Debian and Slackware) are very useful sources of the source code of ancient versions of some free software.

The origin of the tiger thus remains unsolved.

2010-12-07

It is a misconception that C++ is a superset of C

This blog post shows (with a counterexample) that C++ is not a superset of C, i.e. there is a valid C program which is not a valid C++ program.

It's easy to find a counterexample: just use a C++ keyword as a variable name in C. The program is int class;. The proof:

$ gcc -v
gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)
$ g++ -v
gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)
$ echo 'int class;' | tee t.c t.cc >/dev/null
$ gcc -c -pedantic -ansi -W -Wall t.c
$ g++ -c t.cc
t.cc:1: error: expected identifier before ‘;’ token
t.cc:1: error: multiple types in one declaration
t.cc:1: error: declaration does not declare anything

There is a counterexample which doesn't contain any C++ keywords. The program is int i=&i;. The code:

$ echo 'int i=&i;' | tee t.c t.cc >/dev/null
$ gcc -c -pedantic -ansi -W -Wall t.c
t.c:1: warning: initialization makes integer from pointer without a cast
$ g++ -c t.cc
t.cc:1: error: invalid conversion from ‘int*’ to ‘int’

There is a counterexample which doesn't contain any C++ keywords, and it compiles without a warning as C code. The program is char *p=(void*)0;

$ echo 'char *p=(void*)0;' | tee t.c t.cc >/dev/null
$ gcc -c -pedantic -ansi -W -Wall t.c
$ gcc -c -pedantic -std=c89 -W -Wall t.c
$ gcc -c -pedantic -std=c99 -W -Wall t.c
$ gcc -c -pedantic -std=c9x -W -Wall t.c
$ gcc -c -pedantic -std=gnu89 -W -Wall t.c
$ gcc -c -pedantic -std=gnu99 -W -Wall t.c
$ gcc -c -pedantic -std=gnu9x -W -Wall t.c
$ tcc -W -Wall -c t.c
$ 8c -c -w t.c
$ g++ -c t.cc
t.cc:1: error: invalid conversion from ‘void*’ to ‘char*’

As a bonus: there is a program source which compiles in both C and C++, but it does something different. The following example is based on the fact that sizeof('x') is 1 in C++, but it's at least 2 in C.

#include <stdio.h>
int main(){return!printf("Hello, C%s!\n", "++"+1%sizeof('x')*2);}

Another idea to make the same program source do something else in C than C++ is to take advantage of that union t (etc.) create a type named t in C++, but not in C.

#include <stdio.h>
char t; int main(){union t{int u;};
return!printf("Hello, C%s!\n", "++"+(sizeof(t)<2)*2);}

So the true statement is: C and C++ are similar languages, with a large common subset, and C++ being much larger to the common subset than C is.

2010-12-05

On browser compatibility issues

This blog post lists the browser compatibility issues (with solutions) I've encountered when creating a simple HTML(4) + JavaScript + CSS web page containing presentation slides with a little bit of user interaction.

My goal was to make the web page compatible with Google Chrome 8.0 or later, Firefox 3.6 or later, Safari in Leopard or later, Opera 10.63 or later, Konqueror 4.4.2 or later, Internet Explorer 8.0 or later. (I'll call them main browsers from now on.) Please note that anything stated in this blog post may not be true for earlier web browser versions. There was no plan to make the web page work in any earlier web browser version, but it turned out that it was possible and easy to make the page work with Internet Explorer 7.0 with some small rendering quality degradation, so I happened to add support for that as well.

My workflow:

  • Edit the web page directly in a text editor, as a single HTML file (containing HTML, JavaScript and CSS). Split it to different files only after the prototype is found working and all browser compatibility issues have been registered (and most of them resolved).
  • Make sure the browser renders the page in standards compliant mode, not in quirks mode (see below how and why).
  • View the local HTML file in Google Chrome, reload the page after each file save. Try it after major modifications in Firefox. As soon as the web page works in these two browsers, fix it for other browsers as well.
  • When porting to other browsers, especially Internet Explorer, search in the jQuery source code for the feature (class or method name) that works in one browser. Most probably they jQuery source will contain its alternative implementations for other browsers.
  • Use the Developer Tools feature of Google Chrome (activate it with Ctrl-Shift-J) to debug the DOM, the CSS and the JavaScript on the current page. With Firefox, use the Firebug extension and/or the shell bookmarklet for debugging. Should you need it, use the Tools / Developer Tools (activate it with F12; it is available as an extension called Developer Toolbar for IE7 and earlier) in Internet Explorer 8 for debugging.
  • With Internet Explorer Developer Tools you can verify that the web page is indeed rendered in standards compliant mode, and you can also force a rendering which Internet Explorer 7 would do.
  • After each major change, validate the web page that it is valid HTML 4.01 transitional. You can use the HTML Validator Google Chrome extension.

My general knowledge and advice on cross-browser compatibility:

  • All main browsers (Google Chrome, Firefox, Safari, Opera and Konqueror) are very similar to each other except for Internet Explorer.
  • Google Chrome, Safari and Konqueror are even more similar to each other, because they share the same original code base (KHTML in Konqueror, which WebKit in Safari is based on, which WebKit in GoogleChrome is based on).
  • Rendering (application of CSS) in most main browsers in much more similar to each other when they render the web page in standards compliant mode rather than in quirks mode. So to get rid of many incompatibilities, just make sure that the browser renders the page in standards compliant mode.
  • To enable standards compliant mode, just start your HTML with a doctype (right at the beginning of the file). To get HTML 4.01 transitional, prepend this to your HTML file:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
  • Make sure your editor saves the HTML file in UTF-8 encoding (character set), without the byte order mark (BOM).
  • Make sure the character set is indicatied the <head>. This is needed and used when the web page is loaded using a file:/// URL or imported to a word processor such as OpenOffice Writer or LibreOffice Writer. Example:
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  • Make sure your webserver returns the proper character set for the web page in the HTTP response headers (e.g. Content-Type: text/html; charset=utf-8). This setting is used for http:// and https:// URLs. The HTTP response header takes precedence over <meta http-equiv=. If you use the Apache webserver, you may be able to force the UTF-8 charset by creating a file named .htaccess (filename starting with a dot) next to the HTML file, containing
    AddDefaultCharset UTF-8
    . If it doesn't seem to take effect, then put an error (temporarily) to the .htaccess file (e.g. nosuchdirective 42), do a Shift-reload on your web page. If that causes an Internal Server Error, then .htaccess is indeed honored by Apache. If you don't get such an error, talk to your webmaster or system administrator (i.e. copy-paste this paragraph to an e-mail in addition to the URL).
  • The corresponding SVN command (for Google Code) for the character set is:
    svn propset 'svn:mime-type' 'text/html; charset=utf-8' webpage.html
  • Use jQuery, and make it take care of most browser compatibility issues. This document assumes, however, that no JavaScript framework is used, so all issues have to be resolved manually.

Some specific cross-browser compatibility issues I have encountered:

  • See a cross-browser comparison of all JavaScript browser events here.
  • Internet Explorer has a different API for installing and handling events.
    • Event propagation and bubbling semantics are different. You can avoid these issues by installing all event handlers for document.body and window. (Sorry, I don't know more about this.)
    • For Internet Explorer, change obj.addEventListener(eventName, handler, false) to obj.attachEvent('on' + eventName, handler).
    • For Internet Explorer, change obj.removeEventListener(eventName, handler, false) to obj.detachEvent('on' + eventName, handler).
    • Internet Explorer supports the DOMContentLoaded event under a different name (onreadystatechange) and different semantics, see below.
    • Internet Explorer needs event.preventDefault() to be specified differently. Here is the cross-browser solution:
      event.preventDefault ? event.preventDefault() : (event.returnValue = false)
    • Internet Explorer needs event.stopPropagation() to be specified differently. Here is the cross-browser solution:
      event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true)
    • Internet Explorer doesn't pass the event object to the event handler function. To make it cross browser, write it like this:
      function handler(event) { if (!event) event = window.event; ... }
  • Internet Explorer doesn't have window.getComputedStyle, so the current (computed) CSS properties have to be queried differently. An example, specific cross-browser solution:
    function getBackgroundColor(element) {
      return element.currentStyle ? element.currentStyle.backgroundColor :
             window.getComputedStyle(element, null).
             getPropertyValue('background-color')
    }
  • Internet Explorer 8 doesn't have elementOrDocument.getElementsByClassName, so it has to be emulated using a loop and e.g. elementOrDocument.getElementsByTagName and some manual checking. The emulation is a bit slower.
  • The string.substr method in Internet Explorer doesn't accept negative values in its first argument, so e.g. myString.substr(-2) has to be replaced by myString.substr(myString.length - 2).
  • The DOMContentLoaded event is fired as soon as the main HTML and the JavaScript and CSS files it references have finished loading — but before images and other objects on the page have finished. By that time, the rendering is done and measurements are made, so e.g. document.body.offsetWidth is valid. In contrast, the onload even fires as soon as images etc. are also finished loading Here is how to handle DOMContentLoaded in a cross-browser way:
    function onDomReady() {
      ...
    }
    if (navigator.userAgent.indexOf(' KHTML/') >= 0) {
      document.addEventListener('load', onDomReady, false) 
    } else if (document.addEventListener) {
      document.addEventListener('DOMContentLoaded', onDomReady, false)
    } else if (document.attachEvent) {
      document.attachEvent('onreadystatechange', function() {
        if (document.readyState == 'complete') {
          document.detachEvent('onreadystatechange', onReadyStateChange)
          onDomReady()
        }
      })
    }
    Here, the load event is used instead of DOMContentLoaded, because Konqueror 4.4.2 doesn't compute element dimensions (e.g. document.body.offsetWidth and CSS properties) at DOMContentLoaded time; but it returns bogus default values. For Internet Explorer, onreadystatechange has to be used instead.
  • There are two keyboard events when a key is pressed or auto-repeated: keydown and keypress.
    • Use keypress for Google Chrome and Safari (i.e. navigator.userAgent.indexOf(' AppleWebKit/') >= 0), because they don't send the arrow key (and any other non-letter) events for keypress.
    • Use keydown for Firefox (for 3.6), because it doesn't send auto-repeats for keydown (see more here).
    • Use onkeydown on Internet Explorer.
    • Some browsers have a meaningless event.keyCode (such as 0 for Firefox 3.6 or the same as the event.charCode for Konqueror 4.4.2) for some keys. In this case, use the event.charCode instead.
    • The event.charCode depends on whether Shift is down (e.g. 65 for A and 97 for Shift-A), but it doesn't depend on whether Ctrl or other modifiers are down. event.charCode is usually a Unicode code point (character code).
    • See event.keyCode constants here.
    • See more here about keyboard event compatibility.
  • Many browsers (such as Firefox 3.6) send multiple resize events (as part of an animation) when the window is maximized.
  • To get the vertical scroll position, use document.body.scrollTop || document.documentElement.scrollTop, because Konqueror always returns 0 for just document.body.scrollTop. Do this respectively for the horizontal scroll position (scrollLeft).
  • To scroll the page in a cross-browser way (which works in Konqueror as well), use window.scroll(newScrollLeft, newScrollTop) .
  • Internet Explorer doesn't support window.innerWidth, use window.innerWidth || document.documentElement.clientWidth for cross-browser compatibility. Do the same with window.innerHeight and document.documentElement.clientHeight as well.
  • Internet Explorer 7 doesn't support an extra comma right before ] and } in array and object constructors.

2010-11-28

Announcing uevalrun: self-contained computation sandbox for Linux

This blog post is to announce uevalrun.

uevalrun is a self-contained computation sandbox for Linux, using User-mode Linux for both compilation and execution of the program to be sandboxed. The program can be written in C, C++, Python, Ruby, Perl or PHP. uevanrun enforces memory limits, timeouts and output size limits in the sandbox. The primary use case for uevalrun is evaluation of solution programs submitted by contestants of programming contests: uevalrun compiles the solution, runs it with the test input, compares its output against the expected output, and writes a status report.

For your convenience, here is a (non-updated) copy of the documenation of uevalrun. See project home page for the most up-to-date version.

Installation

A 32-bit (x86, i386) or 64-bit (x86_64, amd64) Linux system is required with enough RAM for both compilation and execution, plus 6 MB memory overhead. The Linux distribution doesn't matter, because uevalrun uses statically linked binaries, and it's self-contained: it contains all the tools it needs, including the C and C++ compilers (from the uClibc gcc-4.1.2 toolchain).

uevalrun doesn't need root privileges: it runs as a simple user.

uevalrun needs about 160MB of disk space, most of which is consumed by the C compiler (31MB extracted + 17MB compressed), the scripting language interpreters (9MB compressed), and the virtual disk images (77MB, uncompressed). After removing all temporary files, 80MB will be enough.

Download and compile:

$ svn co http://pts-mini-gpl.googlecode.com/svn/trunk/uevalrun uevalrun
$ cd uevalrun
$ ./make  # This downloads some more files during compilation.

Try it (the italic parts are displayed by the program):

$ (echo '#! perl'; echo 'print "Hello"x2, "\n"') >foo.pl
$ echo HelloHello >expected.txt
$ ./uevalrun -M 10 -T 9 -E 9 -s foo.pl -t /dev/null -e expected.txt
...
@ result: pass
$ echo '/**/ int main() { return!printf("HelloHello\n"); }' >foo.c
$ ./uevalrun -M 10 -T 9 -E 9 -U 19 -N 32 -C 9 \
  -s foo.c -t /dev/null -e expected.txt
...
@ result: pass

How to use

This section has not been written yet. If you have questions, don't hesitate to ask!

Requirements

Security is the most important requirement of uevalrun, followed by high performance and usability.

The sandboxing must be secure, more specifically:

  • Programs inside the sandbox must not be able to communicate with the outside world, except for their stdin and stdout. So they don't have access to the filesystem (except for some read-only access to some whitelisted system libraries and binaries), and they can't do network I/O. If uevalrun is used for programming contest submission evaluation, this restriction prevents the program from finding and reading the file containing the expected output.
  • Sandboxed programs must not be able to use more system resources (memory, disk, CPU) than what was allocated for them.
  • Sandboxed programs must not be running for a longer period of time than what was allocated.
  • Even the compilation of programs to be run (executed) inside the sandbox must be sandboxed (possibly with different system resource allocation), to prevent the attacker from submitting a program source code which exploits a bug in the compiler.
  • The sandbox must be reverted to its initial state before each compilation and execution, so sandboxed programs won't be able to gather information about previous compilations and executions. For programming contests, this restriction prevents the program from reading other contestants' submissions or their output.
  • Timeouts (both real time and user time) must be enforced outside the sandbox, so the program will be reliably killed if it runs for too long time, even if it tampers with time measurement inside the sandbox.
  • Sanboxed programs must not be able to lie about their success, their performance or the correctness of their output by writing special marker characters to their stdout or stderr.

The sandbox must be fast and waste few resources, more specifically:

  • Reverting the sandbox to its initial, empty state must be very fast (preferably faster than 1 second).
  • Starting a program inside the sandbox must be very fast (preferably faster than 1 second).
  • Running a program inside the sandbox must not be much slower than running the same program outside the sandbox. If the program is CPU-intensive, it may run 1.1 times slower (i.e. 10% slower) inside than outside. If the program is I/O-intensive, it may run 10 times slower inside than outside. This requirement is intentionally quite loose on I/O virtualization performance.
  • Running a program inside the sandbox must not need more than 10MB more memory than running the same program outside.
  • Running a program inside the sandbox must not need any disk space, except for the disk space needed by the program binary, the test input and the expected output, all stored as files outside the sandbox.
  • Compilation inside the sandbox must require only a reasonable amount of temporary disk space (for the file to be compiled, the temporary files, and the output binary).

The sandbox must be easy to use and versatile, more specifically:

  • Sandboxed programs must be able to accept any 8-bit binary input (stdin).
  • Sandboxed programs must be able to write any 8-bit binary output to their stdout.
  • Multiple sandboxed programs must be able to run at the same time on the same host system, without affecting each other.
  • If a sandboxed program fails (e.g. because it writes to its stdout different from what was expected, or it does a memory access violation, it reaches a timeout, it exceeds its allocated memory etc.), the proper failure reason has to be reported (e.g. ``wrong answer'' must not be reported if the program times out or vice versa).
  • The sandboxing software must have as little few system dependencies as possible. It must be able to run in a restricted (e.g. chroot) environment, it must not depend on system libraries or configuration. It must work on 32-bit (x86, i386) and 64-bit (x86_64, amd64) Linux systems, on any Linux distirubution.
  • Sandboxed programs can be written in C, C++, Python, Ruby, Perl and PHP, or in any language whose compiler can produce a 32-bit (i386) Linux statically linked executable binary.

Design

To fullfill the requirements, the following fundamental building blocks are used.

User-mode Linux (UML) is used for virutalization: both compilation and execution is performed in a UML guest, reading data from the host system using virtual block devices (ubd), and writing its output to its /dev/tty1 (con0), which can be read by a process on the host. A UML guest kernel (currently 2.6.31.1) tailered to the sandboxing requirements (security and performance) is configured and compiled. Some kernel patches are applied to increase security, reliability and performance. (Please note that these patches apply to the UML guest kernel only, so the host remains unpatched, and rebooting is not needed either.) Networking and the virtual file system are disabled in the UML guest kernel for increased security. All unnecessary drivers and features are removed from the UML guest kernel to get fast boot times and to reduce the overhead.

The underlying virtualization technology used by UML is ptrace(), which doesn't need root privileges or a kernel module or kernel modifications in the host. As an alternative to UML, Seccomp could be used for sendboxing, but that's quite cumbersome, because the sandboxed process cannot allocate memory for itself (see the Google Chrome Seccomp sandbox for a generic solution), but it's still prohibitively cumbersome to sandbox GCC this way (with its requirements for forking and creating temporary files). Most sandboxing approaches on Linux require root privileges for a short amount of time (for chroot, PID namespaces (see clone(2)) and other namespaces). Most virtualization approaches (like KVM, Xen, VirtualBox, except possibly for QEMU) need loading of kernel modules or patching the kernel, and support only slow guest boot times.

With UML, it's possibly to boot the UML guest, run a hello-world binary, and halt the UML guest in less than 0.02 second (sustained). For that speed, one needs a (guest) kernel patch (included and automatically applied in uevalrun) which skips the Calibrating delay loop kernel startup step, which usually takes 0.33 second. The memory overhead of UML is also quite low (6 MB with a stripped-down kernel).

All software running inside and outside UML is written in C (for high performance) and compiled with uClibc and linked statically to avoid depending on the libc on the host, and to avoid the need for installing a libc in the guest. (The total size of these custom-built binaries is less than 100kB.) There is no Linux distribution installed the guest – only a few custom binaries are copied, like a custom /sbin/init, which mounts /proc, sets up file descriptors and resource limits, and starts the sandboxed program, and then halts the guest. The /lib directory in the guest is empty, except for compilation, where /lib contains libc.a, libstdc++.a etc.

BusyBox (statically linked with uClibc) is used as a Swiss Army Knife tool for scripting and automation (of the build and the setup process), both inside and outside UML. Please note, however, that once all the binaries are built and the filesystem images are created, BusyBox is not used anymore for running sandboxed programs and evaluating their output (except for temporary filesystem creation) because of performance reasons, but work is done by the small and fast custom C tools just compiled.

Sandboxed program sources can be written in C (using a large subset of uClibc as the system library), C++ (using uClibc and libstdc++), Python (using all the built-in Python modules), Ruby (using just the built-in Ruby modules and classes which are implemented in C), Perl (using only the few dozen most common modules), or PHP (using just the built-in PHP functions which are implemented in C).

For C and C++ compilation, a GCC 4.1.2 toolchain is used which is based on uClibc and produces statically linked executables.

Interpreters for Python, Ruby, Perl and PHP are provided as precompiled, self-contained, single, statically linked, 32-bit (i386) Linux executables. It's easy to copy them to the /bin directory of the UML guest.

All tools used for building the software are either shipped with the software, or the software downloads them during compilation. All binary tools are statically linked, 32-bit (i386) Linux executables. This provides maximum host system compatibility and reproducible behavior across systems.

In our speed measurements, CPU-intensive programs running inside UML run 1% slower than outside UML, but I/O-intensive programs (such as C++ compilation with GCC) can be about 6 times slower.

The Minix filesystem is used in the UML guests for both read-only filesystems (e.g. the root filesystem with the scripting language interpreters) and read-write filesystems (such as /tmp for the temporary assembly files created by GCC). The Minix filesystem was chosen instead of ext2 and other usual Linux filesystem, because it has less size overhead, it's codebase is smaller, and it has equally good performance for the small and mostly read-only filesystems it is used for.

License

uevanrun has been released under the GNU GPL v2.

Bugs? Problems? Contact the author. Send feedback!

Please add your feedback to the issue tracker. All feedbacks are welcome.

2010-11-19

How to download Skype without having to register

Recently Skype has introduced the requirement of registration or logging in on its web page before downloading the Windows version of their Skype software. This blog post explains how to download Skype without registration or logging in.

Follow the link relevant to your operating system:

2010-11-15

Remote desktop sharing for Linux without software installation and firewall configuration

This blog post explains how to share two desktops (screen, keyboard and mouse) without software installation (on Linux) and firewall configuration. The instructions given have been verified on Ubuntu Lucid running on 32-bit (i386) and 64-bit (amd64) architecture -- but they should work on any modern Linux desktop.

TeamViewer is an excellent cross-platform application which provides desktop sharing, file transfer, chat and video conferencing, and it's free for personal use. Its use is straightforward. Installers for Linux, Mac OS X, Windows and iPhone are downloadable here.

If you don't want to install anything, you can try the QuickSupport edition of TeamViewer on Windows and the Mac OS X. (Get it from the same download page.) The QuickSupport edition doesn't let the user initiate a connection (to become a client), but it listens as a server waiting for connections.

As of now, there is no official Linux QuickSupport edition of TeamViewer, so I've created one; it downlads and starts the regular TeamViewer for Linux application, without installing it. To use it on a vanilla Ubuntu Lucid box, just press Alt-, and type (or copy-paste) the following command, and press Enter:

bash -c 'wget -O- goo.gl/k9imm | bash'

Please note that the O between the dashes is a capital O. All other characters are lowercase.

Remote desktop sharing for Linux without software installation and firewall configuration

This blog post explains how to share two desktops (screen, keyboard and mouse) without software installation (on Linux) and firewall configuration. The instructions given have been verified on Ubuntu Lucid running on 32-bit (i386) and 64-bit (amd64) architecture -- but they should work on any modern Linux desktop.

TeamViewer is an excellent cross-platform application which provides desktop sharing, file transfer, chat and video conferencing, and it's free for personal use. Its use is straightforward. Installers for Linux, Mac OS X, Windows and iPhone are downloadable here.

If you don't want to install anything, you can try the QuickSupport edition of TeamViewer on Windows and the Mac OS X. (Get it from the same download page.) The QuickSupport edition doesn't let the user initiate a connection (to become a client), but it listens as a server waiting for connections.

As of now, there is no official Linux QuickSupport edition of TeamViewer, so I've created one; it downlads and starts the regular TeamViewer for Linux application, without installing it. To use it on a vanilla Ubuntu Lucid box, just press Alt-, and type (or copy-paste) the following command, and press Enter:

bash -c 'wget -O- goo.gl/k9imm | bash'

Please note that the O between the dashes is a capital O. All other characters are lowercase.

2010-11-10

How to disable PulseAudio on Ubuntu Lucid and Oneiric without uninstalling it

This blog post explains how to disable PulseAudio on Ubuntu Lucid without uninstalling it. The solution described here may work on other Linux distributions as well. Please note that you may lose volume controls integrated to GNOME (e.g. the volume control hotkeys), and you'll have to adjust the volume with alsamixer or it's GNOME equivalent, gnome-alsamixer.

Install the volume control programs:

$ sudo apt-get install alsa-utils gnome-alsamixer
$ sudo apt-get remove gamix  # Applications / Sound & Video / ALSA Mixer

Stop the PulseAudio server (pulseaudio) and remove temporary files:

$ pkill -STOP '^pulseaudio$'
$ rm -rf ~/.pulse

Make sure all application attempts to connect to the PulseAudio server and/or to start a new PulseAudio server will fail:

$ mkdir -p ~/.pulse
$ (if grep -q \=10 /etc/lsb-release; then
     echo 'default-server = 0.0.0.1'
   else
     echo 'daemon-binary = /dev/null/no-daemon'
   fi
   echo 'autospawn = no') >~/.pulse/client.conf

Kill the PulseAudio server:

$ pkill -KILL '^pulseaudio$'

Optionally, to disable PulseAudio for all users, add the following lines to /etc/pulse/client.conf for Ubuntu Lucid:

default-server = 0.0.0.1
autospawn = no
The corresponding lines for Ubuntu Oneiric are:
daemon-binary = /dev/null/no-daemon
autospawn = no

Restart your web browsers (for the Flash Player) and your Skype, and possibly other applications which use sound. To do so, it's best to log out and log in again.

2010-11-03

How to get rid of the GNOME panel menu delay on Ubuntu Lucid

This blog post gives instructions how to get rid of the GNOME panel menu delay, i.e. the small delay one experiences when moving the mouse pointer over the System menu, and the submenus like Preferences and Administration don't open immediately. The solution shown has been tested on Ubuntu Lucid, but it might work on other systems as well.

Run the following command to configure newly started applications to omit the delay:

$ echo "gtk-menu-popup-delay = 0" >> ~/.gtkrc-2.0

Run this command to restart the GNOME panel currently running:

$ killall gnome-panel
If you are interested speeding up the loading of icons, see more information on http://www.ubuntugeek.com/how-to-make-gnome-menus-faster-in-ubuntu.html.