Fun with manpages

When reading about a Unix command or C library function it's relatively common to see it suffixed with a number in brackets. This is to make it clear what exactly you're talking about, so if someone is discussing mknod they might write mknod(1) they're talking about the shell command or mknod(2) if they mean the syscall. The number used refers to the manpage section, so to see the manpage for the shell function:

$ man 1 mknod

And to see what the syscall is all about:

$ man 2 mknod

According the man manpage on my system there are eight standard manpage sections in total, with one non-standard section:

  1. Executable programs or shell commands
  2. System calls (functions provided by the kernel)
  3. Library calls (functions within program libraries)
  4. Special files (usually found in /dev)
  5. File formats and conventions eg /etc/passwd
  6. Games
  7. Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
  8. System administration commands (usually only for root)
  9. Kernel routines [Non standard]
Since something can be present in more than one section, I wondered which symbol had the most manpages so I wrote a script to look through each of the directories in /usr/share/man/man[1-8], list and parse the gzipped filenames (they're usually named symbol.sectionnumber.gz) and then find out the sections they're all present in:
import os
import re
from collections import defaultdict

manpage_gz_pattern = "(.*)\.\w+.gz"
manpage_dir_base = "/usr/share/man"
manpage_sections = range(1, 9)
manpage_entries = defaultdict(list)

for manpage_section in manpage_sections:
    manpage_section_dir = os.path.join(manpage_dir_base, f"man{str(manpage_section)}")
    manpage_section_contents = os.listdir(manpage_section_dir)

    for manpage_entry_filename in manpage_section_contents:
        gz_entry = re.match(manpage_gz_pattern, manpage_entry_filename)
        manpage_entry = gz_entry.groups()[0] 
        manpage_entries[manpage_entry] += [(manpage_section, manpage_entry_filename)]

for section_count in manpage_sections:
    number_of_manpages = len([ m for m in manpage_entries if len(manpage_entries[m]) == section_count])
    print(f"number of manpages in {section_count} sections: {number_of_manpages}")

The results are:
$ python -i mancount.py
number of manpages in 1 sections: 10763
number of manpages in 2 sections: 107
number of manpages in 3 sections: 7
number of manpages in 4 sections: 0
number of manpages in 5 sections: 0
number of manpages in 6 sections: 0
number of manpages in 7 sections: 0
number of manpages in 8 sections: 1
There's seemingly a clear winner, you can find a single symbol in all eight standard manpage sections. However this is a little misleading because after a bit of inspection this symbol is "intro" - it is not a shell command, syscall, stdlib function, game or anything like that - it's a manpage that describes a bit about each section.

So ignoring intro the most common symbols and their manpage entries are
  • mdoc (mdoc.1.gz, mdoc.5.gz, mdoc.7.gz)
  • locale (locale.1.gz, locale.5.gz, locale.7.gz)
  • hostname (hostname.1.gz, hostname.5.gz, hostname.7.gz)
  • passwd (passwd.1ssl.gz, passwd.1.gz, passwd.5.gz)
  • time (time.2.gz, time.3am.gz, time.7.gz)
  • readdir (readdir.2.gz, readdir.3am.gz, readdir.3.gz)
  • random (random.3.gz, random.4.gz, random.7.gz)
This reveals something else interesting - the section needn't be a number. The two commands are both valid and access completely separate manpages:

$ man 1ssl passwd
$ man 1 passwd

I used to think that each time I opened a manpage I learn something completely new and unexpected - but I never thought I'd find something interesting just by looking at the manpages' gzipped filenames!

Debian - Building XMMS 1.2.11 on a modern linux system

Like most people I've recently been consuming all my media via paid streaming services like Netflix and iTunes. The other day however I needed to play an MP3 on my laptop running Debian and instinctively wanted to reach for xmms. Sadly nowadays the original xmms isn't available on Debian, only an "xmms2" package which is much newer and was reworked into some client/server model. I don't really want to figure out how to configure this correctly, to the extent that I was willing to build the original xmms from source ...

Trying the naive "./configure && make && sudo make install" method doesn't go very well when running Debian stretch:
sean@seoul ~/d/s/xmms-1.2.11> ./configure
checking build system type... x86_64-unknown-linux-gnu

MANY LINES LATER

*** The glib-config script installed by GLIB could not be found
*** If GLIB was installed in PREFIX, make sure PREFIX/bin is in
*** your path, or set the GLIB_CONFIG environment variable to the
*** full path to glib-config.
configure: error: *** GLIB >= 1.2.2 not installed - please install first ***
As it turns out I wasn't able to find a pre-built version of GLIB 1.x or (a subsequent dependency) GTK 1.x, I found some sources (GLIB 1.2 and GTK+ 1.2) but these were hitting an error when running ./configure which indicated that the CPU wasn't supported. These libraries pre-date the x86-64 era so my processor wasn't recognised. The fix was to simply drop in a newer config.sub. There was one more issue with the G_GNUC_PRETTY_FUNCTION macro but I resolved that too - I put them onto GitHub as glib-1.x and gtk-1.x in case anyone else wants to use this. Installing them is easy:
$ git clone https://github.com/smcl/gtk-1.x
$ cd gtk-1.x
$ ./configure --prefix=/usr && make
$ sudo make install

$ git clone https://github.com/smcl/glib-1.x
$ cd glib-1.x
$ ./configure --prefix=/usr && make
$ sudo make install
Once these are in place we can grab the "latest" old XMMS sources from xmms.org and build those:
$ curl -LO http://www.xmms.org/files/1.2.x/xmms-1.2.11.tar.gz
$ tar -xzf xmms-1.2.11.tar.gz
$ cd xmms-1.2.11
$ ./configure && make
$ sudo make install

Then if all is well then the original (and best!) xmms should be installed into your path, so you can go download some lovely skin of a brushed aluminium late-90s Sony CD player ... though it might be a little bit tiny if you use a HiDPI screen:


Firefox Developer - Gnome and Debian 9 quickstart

Using Firefox on Debian 9 is a little frustrating as the packages available from default APT sources are older “ESR” releases (firefox-esr, 52.0 at the time of writing). Getting the Dev or Nightly builds is pretty straight forward but if you use Gnome you probably want a launcher, and it might not be very obvious how to do this.

First grab the sources or prebuilt binaries:

    $ curl -LO "https://download.mozilla.org/?product=firefox-devedition-latest-ssl&os=linux64&lang=en-US"

Extract them into /opt/firefox-dev:

    $ tar -xjf firefox-57.0b12.tar.bz2 && sudo mv firefox /opt/firefox-dev

Open up a text editor and create /use/share/applications/firefox-dev.desktop as follows

    [Desktop Entry]
    Name=Firefox Dev
    Comment=Browse the World Wide Web
    GenericName=Web Browser
    X-GNOME-FullName=Firefox Dev Web Browser
    Exec=/opt/firefox-dev/firefox %u
    Terminal=false
    X-MultipleArgs=false
    Type=Application
    Icon=firefox-dev
    Categories=Network;WebBrowser;
    MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/vnd.mozilla.xul+xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;
    StartupNotify=true

Copy the icon and run gtk-update-icon-cache so that the icon appears as expected.

    $ sudo cp /opt/firefox-dev/browser/icons/mozicon128.png /usr/share/icons/hicolor/128x128/apps/firefox-dev.png
    $ sudo gtk-update-icon-cache -f /usr/share/icons/hicolor

And that's it! You should have a nice desktop icon for Firefox Developer Edition you can use. I also did the same for Firefox Nightly:

For updates you can clean out the directory and repeat the process with the latest tar.bz2 file ... or you can change the permissions in the firefox-dev directory so you have write access, and auto-updates will work.







Discover a Linux Utility - ischroot

When I open up dmenu and start typing out the program I want to open it provides some autocomplete suggestions based on the programs in my PATH.

I realised that there are hundreds of these, most of which I have never heard of before in my life. I realised that without a concerted effort I'd actually never end up learning anything about most of them - so I wrote a quick one liner to choose a random utility from my PATH and open up the man page:

    $ (for folder in `echo $PATH | sed "s/:/\\n/g"`; do ls -1 $folder; done; ) | shuf -n 1 | xargs man
How this works is basically splitting my PATH into new lines using sed, then listing the contents using one calling ls -1 and selecting one from the whole lot using shuf and attempting to open its manpage using man.

The first one I picked up was ...

Oh nice - ischroot. Well as the manpage says, this detects if we're currently running in a chroot. OK another quick mystery solved...

However that's doesn't exactly help us understand the whole picture. So let's start by asking "what is a chroot"? Well say we have a system that has a pretty straightforward set of folders in its root directory like the following

    $ echo $PATH
    /usr/bin:/bin
    $ ls /
    bin  boot  dev  etc  home  initrd.img  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  vmlinuz

So when we run a command like 'ls' it'll look for the utility in the two folders in our PATH (/bin and /usr/bin), then execute it on root directory of our file system. If we want however we can do a little trickery, and use the utility chroot so that when ls runs it sees an entirely different root altogether.

To try this we'll need to prepare our fake root directory:

    $ sudo mkdir /opt/fakeroot
    $ sudo debootstrap --arch i386 jessie /opt/fakeroot http://httpredir.debian.org/debian
    I: Retrieving Release 
    I: Retrieving Release.gpg 
    I: Checking Release signature
    I: Valid Release signature (key id 75DDC3C4A499F1A18CB5F3C8CBF8D6FD518E17E1)
    ... many lines later ...
    I: Configuring tasksel...
    I: Configuring tasksel-data...
    I: Configuring libc-bin...
    I: Configuring systemd...
    I: Base system installed successfully.
    $ ls /
    bin  boot  dev  etc  home  initrd.img  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  vmlinuz
    $ ls /opt/fakeroot/
    bin  boot  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

OK so we now have a similar looking set of folders in /opt/fakeroot that we'd have in a freshly built Debian Jessie system - however we can run ls / using the chroot command so that it sees /opt/fakeroot as its root directory:

    $ sudo chroot /opt/fakeroot ls /
    bin  boot  dev	etc  home  lib	media  mnt  opt  proc  root  run  sbin	srv  sys  tmp  usr  var

OK nice, I can trick a process I've launched into thinking that any directory is root. However if I am launching a process like ls using chroot then surely I have no need for a tool like ischroot? Well the painful truth is that you may be running in a chroot "jail" without even knowing it. Some crafty (or security conscious) sysadmin may have set the system up so that, for example, when you connect via SSH your session is run inside a chroot. So assuming you've been entrusted with sudo priviledges, you can run ischroot and you'll be able to find out whether you are or not.

So just to replay the man page information, the return value of running ischroot should indicate whether we're running inside a chroot or not - the possible return values are:

value meaning
0 running in a chroot
1 not running in a chroot
2 error occurred

So to test this out, let's run ischroot outside a chroot jail ...

    root@hanoi:/opt# ischroot
    root@hanoi:/opt# echo $?
    1

Cool, so that is exactly as expected. So if we switch over to our newly created chroot and run the same command...

    root@hanoi:/opt# sudo chroot /opt/fakeroot
    root@hanoi:/# ischroot
    root@hanoi:/# echo $?
    2

Ah, so instead of returning 1 we got 2 - indicating an error. After a bit of messing around it turns out we have just hit debian bug #685034 -" debianutils: ischroot fails to detect if it is running in a chroot". However we can determine if we definitely are not running in a chroot, but we have a bit of difficulty determining whether or not we are - a return value of 2 could be thought of as a "maybe". Since we don't like "maybe" in some cases, we can force ischroot to interpret "maybe" as "yes" using the -t flag:

    root@hanoi:/# ischroot -t
    root@hanoi:/# echo $?
    0

So not exactly a great start! However I am glad I learned about creating a chroot jail, even if ischroot isn't working as expected. Hopefully the next utility I pick up works a little better (and involves a smaller writeup).

Thinkpad X250 - Debian (cont'd)

After my original effort to get Debian to play nice on the X250 there were still a handful of things which weren't right. This mostly covers the remainder of the things that I had trouble with.

Automatically updating timezone based on location

I was recently in Vietnam and had to update my timezone manually - which was a minor inconvenience. There's an app called tzupdate which will attempt to determine your location and update the timezone accordingly whenever you run it. We can create a cron job to run tzupdate regularly to ensure the timezone is updated:

    $ sudo pip install -U tzupdate
    $ sudo crontab -e

enter the following - it'll cause tzupdate to run on the hour, every hour

    0 * * * * tzupdate

Two-fingered scroll left/right

When setting up my touchpad I neglected to setup the left/right scrolling - adding the followng line to /etc/X11/xorg.conf.d/50-synaptics.conf resolves this:

    Option "HorizTwoFingerScroll" "1"

For more info on the Synaptics touchpad driver, as always ArchLinux has some excellent documentation on the subject.

iPhone - Bluetooth and USB tethering 

Connecting over bluetooth is a little funny and can trouble you in unpredictable ways. Basically network manager overwrites /etc/resolv.conf when it connects/disconnects from a network and blueman doesn't touch it. So as you connect/disconnect from networks your bluetooth connection can be effectively useless as it'll be unable to resolve DNS queries (I'm guessing most people go to http://facebook.com and not http://31.13.76.68)

Easiest way is to prevent network manager from touching resolv.conf - and make sure you have a handful of good nameservers you can rely on. To do this edit /etc/NetworkManager/NetworkManager.conf and add the following to the [main] section:

    dns=none

Then add a handful of dns services to  /etc/resolv.conf:

    $ cat > /etc/resolv.conf << RESOLVEND
    #Google Public DNS
    nameserver 8.8.8.8
    nameserver 8.8.4.4
    
    # OpenDNS
    nameserver 208.67.222.222 
    nameserver 208.67.220.220
    RESOLVEND

Connecting over USB is a little easier

    $ sudo modprobe ipheth

If you're having trouble then apparently ipheth sometimes requires the iphone filesystem to be mounted - which means installing ifuse:

    $ sudo apt-get install libimobiledevice-dev libfuse-dev
    $ git clone https://github.com/libimobiledevice/ifuse
    $ cd ifuse/
    $ ./autogen.sh && ./configure && make && sudo make install
    $ mkdir ~/iPhone && sudo ifuse ~/iPhone

Thinkpad X250's Mobile Broadband setup (Vodafone CZ)

I had a bit of a nightmare of a time connecting to Vodafone using the builtin 4G modem. I think the main thing is that most places on the internet say that for pre-paid SIM you should set the APN to "ointernet" - when actually "internet" is correct. However I did find that I needed to set prefer_mbim to Y for the device:

    $ sudo echo "options cdc_ncm prefer_mbim=Y" >> /etc/modprobe.d/cdc_ncm.conf
You can either setup the connection using the NetworkManager UI and make it match the below:
... or manually create a file in /etc/NetworkManager/system-connections/ like the below:
    $ sudo cat /etc/NetworkManager/system-connections/Vodafone\ CZ
    [connection]
    id=Vodafone CZ
    uuid=2756323d-e364-49dc-9d86-92b8c2a44d15
    type=gsm
    autoconnect=false
    permissions=
    secondaries=

    [gsm]
    apn=internet
    number=*99***1#
    password-flags=1
    pin=1234

    [serial]
    baud=115200

    [ipv4]
    dns=8.8.8.8;
    dns-search=
    method=auto
 
    [ipv6]
    addr-gen-mode=stable-privacy
    dns-search=
    ip6-privacy=0
    method=auto

XTerm looks weird in XFCE

I've since moved nearly full-time to using Xmonad, but when I go back to XFCE and try to use xterm it has an extremely tiny font:

To make them appear a little nicer we need to edit ~/.Xresources - so that it looks like the below

Then fix up .Xresources:

    $ cat .Xresources 
    XTerm*faceName: Source Code Pro
    XTerm*faceSize: 10
    XTerm*metaSendsEscape: true
    ! Fonts {{{
    Xft.antialias: true
    Xft.hinting:   true
    Xft.rgba:      rgb
    Xft.hintstyle: hintfull
    Xft.dpi:       120
    ! }}}

After you restart X and relaunch an xterm everything should appear little nicer

Debian - verifying a downloaded ISO image

Part of something I'm doing involved flashing a Debian live image to a USB thumb drive, which is a pretty straightforward process. However this time I realised that I always ignore the little checksum and signature files that sit alongside them and that if I wanted to use them to verify the integrity/security of the image I had no idea how. So here's a quick HOWTO describing the process I followed.

I needed to use a Debian non-free live image since the Thinkpad X250 has an intel wifi device which requires a closed source firmware blob:

    $ wget -c http://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/8.3.0-live+nonfree/amd64/iso-hybrid/debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso
    $ wget http://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/8.3.0-live+nonfree/amd64/iso-hybrid/SHA512SUMS.sign
    $ wget http://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/8.3.0-live+nonfree/amd64/iso-hybrid/SHA512SUMS

Firslty we need to check that the signature of the sha512sum file was created by someone we trust

    $ gpg2 --verify SHA512SUMS.sign SHA512SUMS
    gpg: Signature made Thu 28 Jan 2016 02:07:24 CET
    gpg:                using RSA key 0xDA87E80D6294BE9B
    gpg: Can't check signature: No public key

In this case gpg2 doesn't have any knowledge of the key used to sign this image - 0xDA87E80D6294BE9B. We'll need to retrieve it from the official Debian key server:

    $ gpg2 --keyserver keyring.debian.org --recv-keys 0xDA87E80D6294BE9B
    gpg: requesting key 0xDA87E80D6294BE9B from hkp server keyring.debian.org
    gpg: key 0xDA87E80D6294BE9B: public key "Debian CD signing key " imported
    gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
    gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
    gpg: Total number processed: 1
    gpg:               imported: 1  (RSA: 1)

Now we have the key we can check the signature, checksums match the key:

    $ gpg2 --verify SHA512SUMS.sign SHA512SUMS
    gpg: Signature made Thu 28 Jan 2016 02:07:24 CET
    gpg:                using RSA key 0xDA87E80D6294BE9B
    gpg: Good signature from "Debian CD signing key " [unknown]
    gpg: WARNING: This key is not certified with a trusted signature!
    gpg:          There is no indication that the signature belongs to the owner.
    Primary key fingerprint: DF9B 9C49 EAA9 2984 3258  9D76 DA87 E80D 6294 BE9B

So the signature is fine, but since we haven't explicitly trusted this key yet we're getting a warning. I'm about 99% sure this is sufficiently secure. Now that is out of the way we can check the ISO using sha512sum:

    $ sha512sum -c <(grep "debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso$" SHA512SUMS)
    debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso: OK

So everything semes to check out and we can be confident the NSA haven't sneakily compromised the image somehow. Just to quickly summarise - here's what we've done:

  1. downloaded a Debian 8.3 live image, checksums and signature
  2. verified the signature was produced by the Debian organisation, and the signature represents the sha512sum 
  3. verified the ISO matches the sha512sum. 


Thinkpad X250 - Debian, XFCE and X.org config

My trusty 2011 Macbook Air started to die recently, and since I'm getting more and more frustrated with OS X (neutering root in El Capitan, for example) I bit the bullet and picked up a Thinkpad X250 on a nice deal and switched to linux full-time. My distro of choice is Debian 8.3 ("Jessie") which is very nice under the hood,but the out-of-the-box UI is a little bit unpolished. Over the last week or so I spent some time bashing it into shape, and since it wasn't so simple I thought I'd share the main steps with anyone else out there.

Display/DPI and Fonts

The first thing is that the X250's screen is 1920x1080 but only 12.5 inches and when you first boot up the text appears to be scaled at 96dpi - and it's pretty tiny. Annoyingly the screen is not high-res enough for the standard HiDPI/Retina approach - scaling everything 2x - to work, everything looks a little too big. Getting something halfway is involves fiddling around with a lot of settings, and this is compounded by the fact that various apps and desktops have different ways of handling it. 

Note that this is mostly for XFCE - some of the other environments look and behave semi-OK (for example Cinnamon is reasonably usable but it eats my battery for breakfast) but I prefer the look and feel of XFCE even if I have to jump through a couple of hoops to get it to play nice.

First thing's first - my display's DPI setting was being incorrectly detected and I didn't have an xorg.conf to modify, so needed to generate one. Logout, switch to a terminal prompt, kill the lightdm process and use Xorg to generate the file:

    $ sudo service lightdm stop
    $ sudo Xorg --configure
    $ sudo cp /root/xorg.conf.new /etc/X11/xorg.conf # or from wherever Xorg created it

Then open up /etc/X11/xorg.conf and edit the Monitor section's DisplaySize - the ThinkPad X250's size in millimetres, so since the X250's screen is 276mm x 155mm we can set it to the following:

    Section "Monitor"
        Identifier "Monitor0"
        VendorName "Monitor Vendor"
        ModelName "Monitor Model"
        DisplaySize 276 155
        Option "DPMS"
    EndSection

After you reboot X11 will have loaded with the correct DPI setting. Things will still look a little wonky - but we're on the right track so sit tight and keep going.

Fixing the XFCE UI element fonts is pretty simple, go to Settings -> Appearance, select the Fonts tab, check the "Custom DPI Setting" box and input 150. 

If you have Chrome or Chromium installed you'll notice that the UI elements and fonts are pretty huge - this is because it's detected that you have a high DPI and has defaulted to scaling things by 2x. You'll need to edit the launcher so that it uses the --force-device-scale-factor to use 1.3 (a number I reached by pure trial-and-error):

Change the following line in /usr/share/applications/google-chrome.desktop:
    Exec=/usr/bin/google-chrome-stable  %U

to 

    Exec=/usr/bin/google-chrome-stable  --force-device-scale-factor=1.3 %U

If you use Chromium you can make a similar change to /usr/share/applications/chromium.desktop. So now Chrome will look a little saner - I also copied over the Times and Helvetica Neue fonts from my Mac and downloaded  Source Code Pro to make things look even better.

Next the login window - we fixed XFCE's DPI but the login window is still using 177, to alter it we need to fix up /etc/lightdm/lightdm-gtk-greeter.conf:

    font-name=Helvetica Neue 8
    xft-antialias=true
    xft-dpi=150
    xft-hintstyle=hintslight
    xft-rgba=rgb
After all this here's what Chrome running with the updated fonts looks like:

Qt fonts

Qt uses some slightly different settings - you need to ensure that ~/.fonts.conf is as appears below:

$ cat ~/.fonts.conf
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <match target="font" >
        <edit mode="assign" name="hinting" >
            <bool>true</bool>
        </edit>
    </match>
    <match target="font" >
      <edit mode="assign" name="hintstyle" >
	<const>hintslight</const>
      </edit>
    </match>
    <match target="font" >
        <edit mode="assign" name="antialias" >
            <bool>true</bool>
        </edit>
    </match>
</fontconfig>

To keep the layout consistent I opened up Settings -> Qt 4 Settings, went to the fonts tab and set it as follows:

Video Playback

I found that video playback was pretty choppy - to resolve it I had to just uncomment out a single option in xorg.conf:

    Section "Device"
        # ... lots of commented out options
        Option     "TearFree"           "true" # <-- uncomment or add this one
        Identifier  "Card0"
        Driver      "intel"
        BusID       "PCI:0:2:0"
    EndSection

Trackpad

Now that things look a little better we can fix the next couple of things that bothered me. By default there's a little area in the corner with counts as a "right" click that personally I don't use. Disabling it was as simple as commenting out the SoftButtonAreas and SecondarySoftButtonAreas in /etc/X11/xorg.conf.d/50-synaptics.conf

    Section "InputClass"
        Identifier "Default clickpad buttons"
        MatchDriver "synaptics"
        #Option "SoftButtonAreas" "50% 0 82% 0 0 0 0 0"
        #Option "SecondarySoftButtonAreas" "58% 0 0 15% 42% 58% 0 15%"
    EndSection

There's another couple of problems - the trackpad is extremely fast and sensitive by default, and additionally scrolling is too fast and has a sort of inertia that irritates me (I found I'd end up accidentally zooming in/out a lot). Scrolling can be tamed by adding the VertScrollDelta, CoastingSpeed and CoastingFriction sections to the same 50-synaptics.conf file as above, under the Driver "synaptics" section:

    Section "InputClass"
            Identifier "touchpad catchall"
            Driver "synaptics"
            MatchIsTouchpad "on"
    # This option is recommend on all Linux systems using evdev, but cannot be
    # enabled by default. See the following link for details:
    # http://who-t.blogspot.com/2010/11/how-to-ignore-configuration-errors.html
    #       MatchDevicePath "/dev/input/event*"
    	Option "VertScrollDelta" "200"
    	Option "CoastingSpeed" "1"
    	Option "CoastingFriction" "200"
    EndSection

For me adding the MaxSpeed option (which controls pointer sensitivity/speed) to 50-synaptics.conf didn't work, so I added the following to my ~/.xinitrc:

    synclient MaxSpeed=1.0 # it is 2.5 by default

The final touchpad tweak is to prevent it from registering touches as clicks while you're typing. XFCE has a setting that looks like it should work, but it leaves an agonising 2 second delay after you type before it enables the touchpad again. There's a handy utility to alter this which is syndaemon.

    syndaemon -i .2 -K -t -R -d

This can also go  into .xinitrc.

Power Management

By default the power management settings are a bit of a farce - my battery was exhausted after a handful of hours use even though it's pretty hefty. Strangely it seems that power management is still a bit of a ridiculous scene, I'd last operated a Linux laptop back in 2007 - a Thinkpad T40 - and sadly the out-of-the-box power management is pretty dire. There's a handful of useful applications which can help with individually tweaking things - like powertop - but thankfully there's a useful utility called tlp which appears to improve things significantly with only a little config required.

First you need to add the correct depot to your /etc/apt/sources.list - so add the following line to the end

    deb http://repo.linrunner.de/debian DIST main

And install the tlp and thinkpad packages:

    $ sudo apt-key adv --keyserver pool.sks-keyservers.net --recv-keys CD4E8809
    $ sudo apt-get update
    $ sudo apt-get install tlp tlp-rdw acpi-call-dkms

I still find power management a little unreliable - when closing the lid the system doesn't always sleep/suspend, the battery charge is sometimes reported incorrectly (it was stuck at "52%" for a while, which I didn't notice before it died on me). In addition XScreenSaver appears to mess things up too - when I enabled its power management settings it would kill performance after resuming from sleep (with the xorg process consuming >100% of the cpu). Disabling this altogether was fine.

Sound

Sound through the built-in speakers worked out of the box for me. However I have a little Bose Soundlink II bluetooth speaker which I like to use that's a little bit tricky. After pairing in blueman (which weirdly was a little bit trial-and-error) I wasn't sure how to get sound to play out of it. The solution was to install PulseAudio Volume Control, a utility that provides a nice graphical interface to controlling PulseAudio:

    $ sudo apt-get install pavucontrol

Then start the process that's playing the sound - so for me it's Chrome as I was watching Netflix. Open up pavucontrol, switch to the Playback tab find your application and select the bluetooth speaker from the dropdown. 

This being manual is a little bit frustrating but it's actually a minor step-up from OS X - where sometimes some apps wouldn't output sound to the speaker.

Conclusion

After the above tweaks my experience on Debian as a user is roughly on par with OS X (as a developer, it's far better of course). However there are still a number of things I am missing which would make my life a lot better.

  • Expose style window switcher. I know that there's skippy-xd but it is pretty buggy. There's an xfce bounty for this, so if anyone fancies picking up a whopping $70 then go nuts: https://www.bountysource.com/issues/3327306-expose-like-task-switcher-for-xfce
  • Trackpad gestures. I was quite fond of multi-touch gestures in OS X to switch workspaces, I haven't got this working in Linux/X.org just yet and I'm not sure if it's available.
  • AirDrop-style file sharing from iPhone

Hopefully I can pick away at those.