Posts tagged ‘linux’

The Hitchhiker’s Guide to an Ioke Dev Env From Source (part 5: Ioke and the REPL)

This is the fifth part in a series of posts for non-experts about setting up an Ioke development environment on Linux. Please see the previous posts to start at the beginning:

This time we will finally get the Ioke source code, build it, and test the Ioke REPL!

Ioke

Ioke uses Git as the source code versioning tool, with a public repository set up on GitHub (soon I’ll be linking like Jeff Atwood).

So – let’s get Ioke using Git by cloning Ola’s repository:

~/bin$ cd ~/work
~/work$ git clone git://github.com/olabini/ioke
Initialized empty Git repository in /home/melwin/work/ioke/.git/
remote: Counting objects: 9221, done.
remote: Compressing objects: 100% (2941/2941), done.
remote: Total 9221 (delta 5782), reused 8656 (delta 5351)
Receiving objects: 100% (9221/9221), 45.95 MiB | 399 KiB/s, done.
Resolving deltas: 100% (5782/5782), done.

Great – let’s quickly move on to the build step:

~/work$ cd ioke
~/work/ioke$ ant
...
     [java] 2606 examples, 0 failures
jar:
      [jar] Building jar: /home/melwin/work/ioke/lib/ioke.jar
 
BUILD SUCCESSFUL
Total time: 22 seconds

Running just ant will execute the default target in the build.xml file. This target will make sure Ioke is compiled and the test suite is run.

At the end is a summary of the test results – if these are not all successful you might have a problem with the environment or you might have checked out a broken build from the repository.

The Ioke REPL

Now all is installed and Ioke is compiled, so let’s fire up the REPL. This is done by just running the main Ioke binary:

~/work/ioke/$ bin/ioke
iik>

When doing this we get the iik> REPL prompt. From here we can execute most Ioke code. Let’s try to print a string:

iik> "Hello World!" println
Hello World!
+> nil
 
iik>

Here we create a Text (Ioke’s string type) literal and send it the message println, which will cause the text to be printed to the console. The return type of println is nil (similar to null), which is printed by the REPL itself. After that we get the prompt back and can execute another line.

Let’s try a little more complex example – the factorial:

iik> fact = method(n, if(n > 1, n * fact(n pred), 1))
+> fact:method(n, if(n >(1), n *(fact(n pred)), 1))

Note how the REPL prints the method definition in a canonical form – it makes it obvious how Ioke parses the code, what are messages and what are arguments.

Let’s run our new factorial function:

iik> fact(3)
+> 6
 
iik> fact(10)
+> 3628800
 
iik> fact(50)
+> 30414093201713378043612608166064768844377641568960512000000000000

Ioke handles arbitrarily big numbers, so we don’t need to think about what fits in a certain number of bits.

The Iik REPL also comes with a simple debugger, which helps with handling conditions. For instance, let’s try to run the fact method, passing a message which doesn’t mean anything (yet):

iik> fact(f)
*** - couldn't find cell 'f' on 'Ground_0xC360E7' (Condition Error NoSuchCell)
 f                                                [<init>:1:5]
The following restarts are available:
 0: storeValue           (Store value for: f)
 1: useValue             (Use value for: f)
 2: abort                (restart: abort)
 3: quit                 (restart: quit)
 
 dbg:1> 1
  dbg:1:newValue> 5
  +> 5
 
+> 120

The above output shows that when we try to reference something that doesn’t exist we get a chance to provide that value. Here I decided to provide a value using the useValue restart and entered the value 5. This let the method continue executing and the result was printed.

To exit the REPL, just type: exit

Next up are the Emacs modes for Ioke – stay tuned!

/M

The Hitchhiker’s Guide to an Ioke Dev Env From Source (part 4: Java+Ant)

This is the fourth part in a series of posts for non-experts about setting up an Ioke development environment on Linux. Please see the previous posts to start at the beginning:

It took a bit longer than anticipated to get to this point, as I got side tracked with the Ioke type checking activities. But now when Ioke S is out we can continue with the series. So! We’re getting closer… Only a few more things to go.

Installing Java

As the current version of Ioke is implemented to run on a Java Virtual Machine, we need to get hold of one of those to be able to continue. The JVM brand we will install here is the latest stable one produced by Sun.

What we need is Java SE Development Kit 6u11 for Linux, Multi-language, and the the filename for this is jdk-6u11-linux-i586.bin. Note that this is not the .rpm.bin, which is also available.

Download the file from http://java.sun.com/javase/downloads/index.jsp (I’m sure you can find it) and put it in the ~/work directory.

To unpack the file, let’s make it executable and then run it:

~$ cd ~/work
~/work$ cd ~/work                   
~/work$ chmod a+x jdk-6u11-linux-i586.bin 
~/work$ ./jdk-6u11-linux-i586.bin         
... lots of legalese here...

Once the license agreement is accepted, the JVM will unpack itself into the directory ~/work/jdk1.6.0_11. Let’s move it to where we want it and add java and javac to the ~/bin directory as before:

~/work$ mv jdk1.6.0_11 ../opt
~/work$ cd ~/bin
~/bin$ ln -s ../opt/jdk1.6.0_11/bin/java
~/bin$ ln -s ../opt/jdk1.6.0_11/bin/javac

And test it:

That done – let’s move on to Ant.

Ant

Ioke uses Apache Ant to handle the build process, so to build Ioke we need to get Ant installed.

Let’s download the Ant distributable package and unpack it in one go – as we did with Git:

~/bin$ cd ~/opt
~/opt$ wget -O - http://www.apache.org/dist/ant/binaries/apache-ant-1.7.1-bin.tar.bz2 | tar xjv
</lang>
 
And add it to the ~/bin directory again so it's on the path:
 
<pre lang="sh">
~/opt$ cd ~/bin
~/bin$ ln -s ../opt/apache-ant-1.7.1/bin/ant

Let’s try it out:

~/bin$ ant -version
Apache Ant version 1.7.1 compiled on June 27 2008

Looking good!

Soon to come: How to get the Ioke source and build it.

/M

Update: Part 5: Ioke and the REPL

The Hitchhiker’s Guide to an Ioke Dev Env From Source (part 3: emacs-starter-kit)

This is the third part in a series of posts for non-experts about setting up an Ioke development environment on Linux. Please see the previous posts to start at the beginning:

The emacs-starter-kit is a set of base configuration for Emacs. It contains a number of useful elisp libraries, with a slight focus on dynamic languages.

To install it, perform the following steps (note that we move any existing Emacs configuration out of the way first to avoid stomping what you currently have):

~/work/emacs$ cd
~$ mv .emacs.d .emacs.d.old
~$ mv .emacsrc .emacsrc.old
~$ git clone git://github.com/technomancy/emacs-starter-kit.git .emacs.d

If you now start Emacs again you’ll see that the menu bar and the toolbar is gone. This is the default in emacs-starter-kit as most Emacs users don’t find them useful. For new users the menu bar can sometimes come in handy, to get it back temporarily, just press F1.

Configuring Emacs

If you want to add your own customizations to Emacs when using emacs-starter-kit, just add an Emacs LISP file called username.el, or hostname.el, in the ~/.emacs.d directory. For instance, to make the menu bar always visible:

  1. Open Emacs, if it’s not open already.
  2. Press C-x C-f and type in: ~/.emacs.d/username.el
    Where username is the name you log in with (for instance, in my case the complete filename is melwin.el).
  3. Type in the following in the file:
    (menu-bar-mode 1)
  4. And save the file with C-x s.
  5. Now quit (C-x c) and restart and you’ll see that the menu bar is shown.

Working with Magit

emacs-starter-kit includes, among many other things, the very nice Magit Git mode for Emacs, which gives you a nice interface for working with a Git repository.

Let’s use this mode to commit our recent changes to the configuration file to our local clone of the emacs-starter-kit repository. This helps us track changes we make and also makes a backup of the file in case we screw (sorry, mess) something up.

Note 1: To move easily between Emacs windows using the keyboard, just press Shift and the arrow key pointing in the direction you want to move.
Note 2: To only show the current Emacs window – press: C-x 1

  1. Inside Emacs, press C-x g to run magit-status and enter the directory (note that Tab auto-completes): ~/.emacs.d
    Emacs magit-status
  2. Put the cursor over the username.el in the list of Untracked files.
  3. Press s to Stage the new file – this adds the file to the Git staging area, from which all files are committed.
    Emacs magit-status staged
  4. Press d and then accept to diff against HEAD – this will show you a diff view of the changes we have staged – just the add of a single file.
    Emacs magit-status diff
  5. Press c to perform the commit. This opens a new buffer into which a commit message can be added.
  6. Write something like: Add personal configuration file.
  7. Now press C-c C-c to commit the file.

That’s it – now the change has been committed to the local clone of the emacs-starter-kit Git repository.

To see the log of all commits, press l (lowercase L) in the magit-status buffer:
Emacs magit-status log

To look at a certain commit – just press Enter on it and a view of the diff will be shown. This makes it quite easy to browse through commits in a repository. At the top of the log is the most recent commit, which in this case is the file we just added.

To update emacs-starter-kit with the latest changes in the GitHub repository, just press F in the magit-status buffer or run git pull in the ~/.emacs.d directory.

Summary

Now that we have Git and Emacs set up we can finally move to Ioke. In the next post we’ll go through installing the latest Java JDK and getting and compiling the Ioke source code.

Join me then!

/M

Update: Part 4: Java and Ant

The Hitchhiker’s Guide to an Ioke Dev Env From Source (part 2: Emacs)

This is the second part in a series of posts for non-experts about setting up an Ioke development environment on Linux. Please see the previous post to start at the beginning:

In this post we will install GNU Emacs from source and also get a basic configuration set up using the emacs-starter-kit.

If you already have Emacs installed and have an old configuration laying around you probably want to make a backup of this before following the below instructions. This post assumes that there is no Emacs installed and that the user doesn’t have any Emacs configuration in the home directory.

Installing Emacs

Git is an efficient Distributed Version Control System. Although the primary VCS for Emacs is still CVS – and it looks like they are moving towards Bazaar – we’ll get the Emacs sources from the Emacs Git mirror. We want to be cool, right?

~$ cd work
~/work$ git clone --depth 1 git://git.sv.gnu.org/emacs.git
Initialized empty Git repository in /home/melwin/work/emacs/.git/
remote: Counting objects: 46400, done.
remote: Compressing objects: 100% (24410/24410), done.
remote: Total 46400 (delta 41204), reused 25501 (delta 21836)
Receiving objects: 100% (46400/46400), 74.38 MiB | 213 KiB/s, done.
Resolving deltas: 100% (41204/41204), done.
Checking out files: 100% (2837/2837), done.

With the --depth 1 parameter we limit the history so that we only get the latest version of the files – in this case we’re not interested in the full history.

Note: As we’re getting the bleeding edge source code of Emacs, it could happen that the build is broken. I’ve never had this happen on me, but in case you get strange errors when building Emacs, this might be the reason. Usually such problems are fixed quickly, so try to do a git pull a bit later to update the downloaded source.

Previously, to get fun things like multi-tty support and smooth fonts, we had to get specific feature branches of Emacs. Nowadays, however, all the things we want are merged into the Emacs master branch. Before building, the only thing we need to do is to make sure the necessary development libraries are installed. In case you wonder how I came up with this list: the good ol’ method of trial and error. I simply ran the configure command and checked the error messages. This helped me identify the needed libraries. Now you can reap the benefits by just doing the following:

~/work$ sudo apt-get install libgtk2.0-dev libxpm-dev libjpeg-dev libgif-dev libtiff-dev
...

… and then run the classical configure, make and make install:

~/work$ cd emacs
~/work/emacs$ ./configure --prefix=$HOME/opt/emacs-23.0.60
...
~/work/emacs$ make
...
~/work/emacs$ make install
...

Phew. That burned som CPU cycles…! Once done – let’s add it to our bin directory, just as we did with Git.

~/work/emacs$ cd ~/bin
~/bin$ ln -s ../opt/emacs-23.0.60/bin/emacs
~/bin$ ln -s ../opt/emacs-23.0.60/bin/emacsclient
~/bin$ ls
emacs  emacsclient  git

Time to test. Just run emacs:

~/bin% emacs

This should show you an Emacs window with a pretty(?) GNU.

Emacs Window

If you’re completely new to Emacs, this might be a good opportunity to run the Emacs tutorial. Emacs is a self-documenting editor, which means that most things that you might want to learn about Emacs can be found inside the editor itself – including information about internal functions and libraries.

To run the tutorial, just press Ctrl+h t (that is, control and h, release control, then press t), or, in Emacs lingo, C-h t (which is the convention I’ll use from now on).

Once you’ve learned enough (you did complete the whole thing, right?), just quit using C-x c.

Note: To update the source code and rebuild, do a git pull in the emacs directory, then make distclean (in case some build files changed) and then perform the compile and installation as per the above again.

Next up is emacs-starter-kit to get more functionality in Emacs and a decent default configuration to help us get going – stay tuned!

/M

Update: Part 3: emacs-starter-kit

The Hitchhiker’s Guide to an Ioke Dev Env From Source (part 1: Git)

In this series of posts I will guide you, the humble reader, through the install procedure to get a development environment for Ioke up and running. All the cool kids want to develop in Ioke nowadays, so let’s make you can as well!

The components we will be installing are:

These instructions are written for a non-expert who might not have too much experience with compiling things, using Git or Emacs. If you’re an expert you will find nothing new or exciting here! The environment I use is a freshly installed Kubuntu Intrepid Ibex box, although most of it should be similar, if not identical, to other Ubuntu/Debian based distributions.

The components listed above will all be installed manually – not using the package system. This is to allow us to get the freshest versions of what we need without depending on the packages in the distribution to be updated (or hunted down in alternative repositories). The only thing we will install from the distribution are the compilers, tools and development libraries used to compile the software.

Why do we not use the package system? Well, that’s a valid question. Most of the above can be installed from packages in custom repositories. It’s simple and convenient. However here we will not use if for two reasons:

  1. If packages are used we will depend on the repositories to be updated to use the latest version of some software, which can be annoying if we want to develop on the bleeding edge.
  2. It’s good to know how to compile things yourself – so by not using prepared packages we might learn something!

To keep control over our custom built software we’ll install it in dedicated directories under $HOME/opt instead of in the normal locations like /usr/bin. This allows us to get everything installed without needing root access (except to install the compilers etc from the distribution).

First Step

Don’t Panic!

Always sound advice to start with – especially if you are hitchhiking. I’m going to try to cover each step in detail, but if you think something is unclear – just leave a comment and I’ll try to clarify. So – grab your towel and let’s get going!

Install Git

For Emacs, emacs-starter-kit and Ioke we will use Git to retrieve the sources. Therefore the first thing we need to install is Git.

In the command line instructions below, all lines prefixed by the prompt <dir>$ are commands to be typed in. The rest are output or my comments.

Open a terminal window and create a new work directory under your home using the following instructions. In this directory we will work with downloaded source files and build the software.

~$ mkdir ~/work
~/work$ cd ~/work
~/work$ wget -O - http://kernel.org/pub/software/scm/git/git-1.6.1.tar.bz2 | tar xjv
... many lines...

The last command downloads the git source package and expands it in one go by piping it directly from wget to tar, which is told to expand it using bz2 with the j parameter. This is a convenient way to get packages off the net and unpacked, especially when there is no need to keep the package itself around.

The result is that we now have a git-1.6.1 directory in the work directory. Let’s see how we compile it:

~/work$ cd git-1.6.1/
~/work/git-1.6.1$ head INSTALL
 
                Git installation
 
Normally you can just do "make" followed by "make install", and that
will install the git programs in your own ~/bin/ directory.  If you want
to do a global install, you can do
 
        $ make prefix=/usr all doc info ;# as yourself
        # make prefix=/usr install install-doc install-html install-info ;# as root
 
~/work/git-1.6.1$

So – two commands. Simple enough! However, before we compile – we need to make sure all the relevant packages are installed:

~/work/git-1.6.1$ sudo apt-get install libcurl4-openssl-dev zlib1g-dev libexpat-dev tk8.5 asciidoc docbook2x

Depending on your internet connection, this could take quite a while, as we need to download the texlive distribution, among other things, to build all of the Git documentation. This is not strictly necessary, but here we’ll just do it for completeness’ sake.

Let’s build git and make sure it’s installed under our $HOME/opt directory as we said in the beginning:

~/work/git-1.6.1$ make prefix=~/opt/git-1.6.1 all doc info
... lots of lines...

Compiling Git will take some time as well. Go get a coffee (or perhaps a Pan Galactic Gargle Blaster – sweet like nectar).

Once the compile is done – install it. Note that we don’t need to do this as root as we’re installing under the user home directory:

~/work/git-1.6.1$ make prefix=~/opt/git-1.6.1 install install-doc install-html install-info

Let’s add it to the user’s path by linking it into the private bin directory. This depends on the standard Ubuntu bash shell profile script which adds ~/bin to the PATH variable. If a different shell is used you need to perform the appropriate steps yourself.

~/work/git-1.6.1$ mkdir ~/bin
~/work/git-1.6.1$ cd !$
~/bin$ ln -s ../opt/git-1.6.1/bin/git

Now close the shell/terminal, open a new one – and try the git command:

~$ git --version
git version 1.6.1

If you get the above output – great! You’re don! Sit back and relax for a bit before moving on to the next section.

However, if you don’t get the version output, but instead see the following message, review the previous instructions and make sure it works ok before continuing.

#INCORRECT OUTPUT - SOMETHING WAS MISSED!
#GO BACK AND REVIEW
~$ git                                                                                                                                                                                        
The program 'git' is currently not installed.  You can install it by typing:                                                                                                                  
sudo apt-get install git-core                                                                                                                                                                 
-bash: git: command not found

If you still can’t get it to work – drop me a comment!

Git in 30 Seconds

There are loads of good Git tutorials and information. You can find several on the official Git page and at GitHub (go sign up if you haven’t already, and fork me!).

Here is a quick run through of a few common Git commands you could try out with your freshly brewed cup of Git:

~$ cd
~$ mkdir gittest
~$ cd gittest/
~/gittest$ git init
Initialized empty Git repository in /home/melwin/gittest/.git/
~/gittest$ echo Test file! > test.txt
~/gittest$ git add test.txt
~/gittest$ git commit -m "Initial import."
[master (root-commit)]: created 79c091d: "Initial import."
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 test.txt
~/gittest$ echo Add line. >> test.txt
~/gittest$ git diff test.txt
diff --git a/test.txt b/test.txt
index 1cbaf90..3746f9e 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
 Test file!
+Add line.
~/gittest$ git commit -a -m "Add new line."
[master]: created b20f9a4: "Add new line."
 1 files changed, 1 insertions(+), 0 deletions(-)

If you can follow the above – great! First part finished. Next up is to install GNU Emacs from source and the emacs-starter-kit, which provides a decent default a set of configuration for Emacs.

Stay tuned!

/M

Update: Part 2: Emacs

DCOP and xmobar

For me, the computer is a work tool that should get out of the way as much as possible to allow me to perform the task at hand. I spend many hours every day working with, primarily, my laptop, and seemingly insignificant improvements to the desktop environment and development tools add up over time to improve my overall efficiency. Because of this I like to spend time looking into how the tools I use can be tuned to better help in what I need to do.

One of the fairly recent chances I’ve made is to switch to a tiling window manager. For those too lazy to read the Wikipedia entry: A tiling window manager automatically arranges the open windows to fill the available space of the screen – saving you the job of arranging the windows yourself. That sounds simple, but can be quite complex in practice.

I started out using Ion3 in mid 2007. Ion3 is nice and smooth and worked great and really got me hooked on tiled window managers. However, as a big fan of open source, I was a bit concerned by the author’s approach to controlling the development of Ion (see this or this for instance) so I switched to wmii. wmii was also quite nice, but I never got into it as well as Ion, for some reason.

That’s when I found xmonad – a very nice window manager written in Haskell. Haskell is also used as the configuration language, which makes the configuration possibilities close to endless (actually, they probably are endless, as Haskell is Turing equivalent (although there are people who doubt it!) :).

Today, some 6 months later, I use xmonad 0.7 together with KDE 3.5.9 (similar to the setup described on the Haskell wiki) on Kubuntu 8.04 and am very happy with it.

Status Bar

However, xmonad is just a tiling window manager, but I also want a status bar to allow me to see chosen pieces of information at a glance. I use KDE3 and have the KDE3 panel kicker running, but it’s hidden unless I put the mouse in the bottom left corner. I don’t use it normally and only keep it around to access the system tray (which I almost never need). Instead of the ugly and bulky kicker I want a smaller, slimmer alternative…

Enter xmobar – a text based status bar, also written in Haskell. xmobar comes with a number of plugins to show different aspects of the system on the status bar – date, cpu, memory, network activity, etc. A few things it doesn’t do out of the box, which I want to see, are number of new mails, current keyboard layout (I use US mainly, but switch to Swedish for the national chars) and speaker mute state. Luckily, xmobar provides a plugin to execute shell commands, and using this mechanism we can put anything on the status bar, as long as we can figure out a command to run to produce the wanted text.

New Mails

I use a Maildir mail storage (together with dovecot to provide an IMAP interface to my mail), and since I don’t automatically split mails into groups/folders it’s enough to just check the number of mails in my Maildir’s new folder. The xmobar command for this ends up as:

Run Com "sh" ["-c", "\"ls ~/Maildir/new | wc -l\""] "mailcount" 600

This command invokes the sh shell and passes a command string using the -c switch. The command string contains the actual shell command we want to execute: ls ~/Maildir/new | wc -l

Executing sh and passing a command string allows us to use the pipe to pass the output of the ls to the wc to get the actual file count back.

The command is mapped to the mailcount alias, and the interval is set to 600 tenths of a second = 60 seconds.

Keyboard Layout

Since I use KDE3 the keyboard layout switching is handled by the kxkb application (shows up as a flag in the tray if multiple layouts are configured). KDE3 uses DCOP (unlike KDE4 which uses D-Bus) for IPC. Available DCOP services can easily be interogated from the command line using the… you guessed it… dcop command.

Running dcop without parameters shows a list of available applications. On my system it shows:

% dcop
konsole-9099
kdebluetooth
kicker
kxkb
guidance-6223
kded
adept_notifier
kmix
knotify
kio_uiserver
klauncher
khotkeys
kwalletmanager
digikam-6484
klipper
ksmserver
knetworkmanager

Woohoo! kxkb is there, so let’s dig deeper. By a bit of trial and error we can probe the internals of the dcop-exposed application:

% dcop kxkb
qt
MainApplication-Interface
kxkb
% dcop kxkb kxkb
QCStringList interfaces()
QCStringList functions()
bool setLayout(QString layoutPair)
QString getCurrentLayout()
QStringList getLayoutsList()
void forceSetXKBMap(bool set)
% dcop kxkb kxkb getCurrentLayout
us

Sweet! Now we have the dcop “path” to find the current keyboard layout. Let’s add it to the xmobar configuration:

Run Com "dcop" ["kxkb", "kxkb", "getCurrentLayout"] "kbd" 20

Speaker Mute State

Using dcop again we can find the mute state:

% dcop kmix
qt
MainApplication-Interface
Mixer0
kmix
kmix-mainwindow#1
% dcop kmix Mixer0
QCStringList interfaces()
QCStringList functions()
void setVolume(int deviceidx,int percentage)
void setMasterVolume(int percentage)
void increaseVolume(int deviceidx)
void decreaseVolume(int deviceidx)
int volume(int deviceidx)
int masterVolume()
void setAbsoluteVolume(int deviceidx,long int absoluteVolume)
long int absoluteVolume(int deviceidx)
long int absoluteVolumeMin(int deviceidx)
long int absoluteVolumeMax(int deviceidx)
void setMute(int deviceidx,bool on)
void setMasterMute(bool on)
void toggleMute(int deviceidx)
void toggleMasterMute()
bool mute(int deviceidx)
bool masterMute()
int masterDeviceIndex()
void setRecordSource(int deviceidx,bool on)
bool isRecordSource(int deviceidx)
void setBalance(int balance)
bool isAvailableDevice(int deviceidx)
QString mixerName()
int open()
int close()
% dcop kmix Mixer0 masterMute
true

Perfect – now we can create the last xmobar run command:

Run Com "dcop" ["kmix", "Mixer0", "masterMute"] "mute" 20

Final Configuration

So, here’s the final .xmobarrc:

Config { font = "xft:Consolas-8"
       , bgColor = "black"
       , fgColor = "grey"
       , position = Bottom
       , commands = [ Run Network "eth0" ["-L","0","-H","32","--normal","green","--high","red"] 50
                    , Run Network "wlan0" ["-L","0","-H","32","--normal","green","--high","red"] 51
                    , Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 52
                    , Run Memory ["-t","Mem: <usedratio>%"] 54
                    , Run Date "%a %b %_d %H:%M:%S" "date" 10
                    , Run StdinReader
                    , Run Com "dcop" ["kxkb", "kxkb", "getCurrentLayout"] "kbd" 20
                    , Run Com "sh" ["-c", "\"ls ~/Maildir/new | wc -l\""] "mailcount" 600
                    , Run Com "dcop" ["kmix", "Mixer0", "masterMute"] "mute" 20
                    ]
       , sepChar = "%"
       , alignSep = "}{"
       , template = "<fc=#ee9a00>%date%</fc> | %cpu% | %memory% | %eth0% - %wlan0% } %StdinReader% { Mail: %mailcount% | Kbd: %kbd% | Mute: %mute%"
       }

And a small screenshot for your viewing pleasure:


(Yes, my laptop’s hostname is dellicious… ;)

Compressed and Encrypted Backup with SquashFS and LUKS

Hardy Heron (KDE flavor) has been out for a while now and this weekend I finally decided to upgrade my (sweet sweet Dell M90) laptop from Gutsy. I used this as justification to get a new Hitachi SATA 200GB 7200RPM disk to replace the old 250GB 5200RPM in an effort to boost performance a little. Getting a new disk also makes the upgrade a lot less risky – I can keep the old disk as it is while setting up the new system.

This time around I decided to get rid of the Windows partition previously used for dual booting (haven’t booted into Windows in 6 months). I also wanted to switch from the extremely useful and amazing Truecrypt to using Linux native LUKS encryption for my work and private data. I originally used Truecrypt on Linux with an NTFS file system to make the encrypted drive compatible with both Windows and Linux, but since then I’ve switched to an ext3 file system and don’t need the capability to mount it both under Linux and Windows. If you do, make sure to try – nay, use! – Truecrypt. It’s very very nice.

So, the 200GB disk ended up being partitioned like so:

$sudo fdisk -l /dev/sda

Disk /dev/sda: 200.0 GB, 200049647616 bytes
255 heads, 63 sectors/track, 24321 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x000cbcfd

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1        3647    29294496   83  Linux
/dev/sda2            3648        7294    29294527+  83  Linux
/dev/sda3            7295       23707   131837422+  83  Linux
/dev/sda4           23708       24321     4931955   82  Linux swap

That is, 30GB for root, 30GB to be encrypted, 135GB for data and the rest for swap.

Of course, with Hardy you can encrypt the root file system just by selecting to do so in the alternate installer, but I don’t feel a need to go that way right now – maybe later.

Backups

Now, slowly approaching the main topic of this post, while playing around with the new disk and the old data I was thinking about putting in place a new backup strategy. At the same time (I can do anything while simultaneously going through my subscriptions in Google Reader:) I happened upon the JWZ post about backups. JWZ, who obviously is a smart guy, is onto something. I’m already doing backups (of part of my data) using rsync to my server at home – not full disk image, admittedly, which was JWZ’s prescription. However, I wanted to try something different and achieve a few other things:

  • Retain multiple snapshots of data at a time
  • Compress the data
  • Encrypt the data

For a while I was considering ZFS (which I in a moment of temporary megalomania started porting to a native Linux kernel module, strictly for private use! – maybe something for another post) with its nice snapshot and compression support, but this idea was quickly discarded for being a bit too unnatural for most Linux setups. I added the additional requirement that the solution should work without having too many non-standard dependencies.

CromFS has a nice feature set, but it’s a FUSE file system and it’s not available in Hardy. The comparison chart on the CromFS page however led me to SquashFS. SquashFS is available out-of-the-box in Hardy and by apt-getting the squashfs-tools package, everything needed is installed. The nice HowTo gives a good introduction to the commands required to use it. Note – SquashFS, as most compressed file systems, is read-only. This suites me perfectly as I want to make a snapshot for backup purposes, but it might not be what you want.

The idea I got was to use SquashFS as the compressed snapshot file system and wrap it in LUKS for encryption. By doing this I get a single compressed file which I can mount on a modern Linux distribution to access the data. It’s securely and (somewhat) efficiently stored.

Luckily, what I wanted to do is very similar to what the Gentoo guide for how to burn and encrypted CD image describes – namely wrapping an already existing file system image in a LUKS encrypted container. Most of the following is based on the Gentoo guide.

There are a few steps to the process:

  1. Create SquashFS image from source data
  2. Create LUKS container
  3. Put SquashFS image inside LUKS container

The trickiest (which isn’t really that tricky) part is figuring out how large to make the LUKS container. As we don’t know beforehand how large the SquashFS image is, we need to create it and then calculate how large the LUKS container should be.

Step 1: SquashFS

Let’s start with creating the SquashFS image:

$sudo mksquashfs /crypt /tmp/cryptbackup.sqsh -e /crypt/stuff
Parallel mksquashfs: Using 2 processors
Creating little endian 3.1 filesystem on /tmp/cryptbackup.sqsh, block size 131072.
[==========================================================================] 2297/2297 100%
Exportable Little endian filesystem, data block size 131072, compressed data, compressed metadata, compressed fragments, duplicates are removed
Filesystem size 13606.69 Kbytes (13.29 Mbytes)
        21.57% of uncompressed filesystem size (63077.89 Kbytes)
Inode table size 38419 bytes (37.52 Kbytes)
        32.62% of uncompressed inode table size (117780 bytes)
Directory table size 33629 bytes (32.84 Kbytes)
        58.10% of uncompressed directory table size (57880 bytes)
Number of duplicate files found 115
Number of inodes 3176
Number of files 1877
Number of fragments 45
Number of symbolic links  945
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 354
Number of uids 5
        ....
Number of gids 12
        ....

This creates a new compressed SquashFS image from the data in the /crypt directory (the contents of this directory becomes the contents of the image root). The -e flag excludes all files in the given directories – here, everything in /crypt/stuff. Note that it might be more efficient to store this image on a separate disk, if available. Even an external USB 2.0 mounted disk might be faster to write to while reading the data from the main disk.

The SquashFS image was compressed by about 50% in my case – 10GB of data stored in a 5GB image. Of course, the compression ratio achieved depends on the type data stored.

Step 2: LUKS Container

Step 1 done, we now need to create a LUKS container to store the SquashFS image in. How big should it be? Well… The Gentoo guide linked to above calculates the size of the LUKS overhead by checking the difference between a LUKS container and the mapped block device. It turns out that this overhead is 1032 blocks (each block being 512 bytes), no matter what the block size is. Googling this seems to confirm it, so for now I’m assuming that LUKS always adds 1032 blocks of overhead.

The size in 512 byte blocks of the SquashFS image can be found by doing:

$ls -l --block-size=512 /tmp/cryptbackup.sqsh
-rwx------ 1 root root 27216 2008-05-11 20:55 /data/cryptbackup.sqsh

Which in the above case indicates that the file is 27216 512 byte blocks large (this is a test file…).

Adding 1032 blocks gives us the size needed for the LUKS container – 28248 blocks – let’s create it (while letting the shell handle the calculation for us):

$sudo dd if=/dev/zero of=/tmp/cryptbackupluks.img bs=512 count=1 seek=$((27216+1032))

Note that this creates a sparse file on most modern file systems, so it’s quite quick. We don’t need to fill it with random numbers or anything as the whole container will be updated when we write the SquashFS image to it.

Now, let’s map it. First locate an available loop device:

$sudo losetup -f
/dev/loop0

loop0 is available – no loops on this system.

Set up the container file as a loop device:

$sudo losetup /dev/loop0 /tmp/cryptbackupluks.img

Then make it a LUKS volume:

$sudo cryptsetup luksFormat /dev/loop0
 
WARNING!
========
This will overwrite data on /dev/loop0 irrevocably.
 
Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase:
Verify passphrase:
Command successful.

Make sure you remember the password… ;P

And open the device:

$sudo cryptsetup luksOpen /dev/loop0 cryptbackup
Enter LUKS passphrase:
key slot 0 unlocked.
Command successful.

Now the device is available as /dev/mapper/cryptbackup, ready to accept our SquashFS image.

Step 3: Put SquashFS Image into LUKS Container

Let’s validate the overhead of LUKS:

$echo $((`sudo blockdev --getsize /dev/loop0`-`sudo blockdev --getsize /dev/mapper/cryptbackup`))
1032

Sweet! So, the size of the mapped device should be the same as our SquashFS image:

$sudo blockdev --getsize /dev/mapper/cryptbackup
27217

Hmmm… Close enough… ;P Perhaps there is some rounding to a full KB or something like that going on. Anywho, at least it is big enough for our 27216 block image. Let’s transfer it:

$sudo dd if=/tmp/cryptbackup.sqsh of=/dev/mapper/cryptbackup bs=512
27216+0 records in
27216+0 records out
13934592 bytes (14 MB) copied, 0.0544451 s, 256 MB/s

Done and done. To verify that it works we can mount the file system:

$sudo mkdir /mnt/cryptbackup
$sudo mount /dev/mapper/cryptbackup /mnt/cryptbackup

If all went well, ls /mnt/cryptbackup should now give the contents of the original directory.

To unmount, do:

$sudo umount /mnt/cryptbackup
$sudo cryptsetup luksClose cryptbackup
$sudo losetup -d /dev/loop0

Now remove the old SquashFS image /tmp/cryptbackup.sqsh and store the LUKS container /tmp/cryptbackupluks.img in a safe location. I use a portable external hard disk and the server at home to save the backup images. To mount later, just run a few of the, slightly modified, above commands again:

$LOOP=`sudo losetup -s -f /tmp/cryptbackupluks.img`
$sudo cryptsetup luksOpen $LOOP cryptbackup
Enter LUKS passphrase:
key slot 0 unlocked.
Command successful.
$sudo mount /dev/mapper/cryptbackup /mnt/cryptbackup

Now, all that remains is to create some helper scripts to avoid having to write all this every time I want to make a backup…

A drawback of this method is that it takes quite a while to perform the backups. It’s not incremental either, so the backups will presumably take longer and longer to make each time (as more data is accumulated). Next thing might be to try to create a base image with SquashFS and then do incremental backups with UnionFS or something… Hmmm……

/M