Hello FreeBSD!

It’s been more than two weeks now that I switched from Linux to FreeBSD. There are multiple reasons behind this change and I will not dwell on all of them. If you read this blog (do you? :)), you probably know that I am a long time advocate of Debian. One particular thing that I like with Debian is that it doesn’t tie your hand with a large set of packages. It is an universal operating system that you can tailor to better suit your needs.

However, as time passes it became harder to modify anything. More and more I find myself patching programs that just want to do things on their own fancy way. More and more some random daemon just gets in my way because it supposedly covers all possible use cases. And recently I came under the impression that my system was just a bunch of layers of layers of various daemons doing their stuff somehow, somewhere, all of them trying to reinvent the wheel, with a twist.

Finally there is one important thing you should remember, Linux is not UNIX. Actually in the past few years, it started to diverge from this philosophy quite significantly. This article presents some differences between the UNIX and the Linux/FLOS model much better than I could do. And this is where we come to the root of my decision. While I can understand some of the benefits of the later approach, it dawns on me that as an user, I do not fit in FLOS and if I keep using Linux as a desktop, this life will be a hell of frustration and ranting without end. Note that this transition was long time foreseeable. I always spent a lot of time with BSDs. However these were casual and experimental setups and I didn’t do much more than porting stuff to it.

I could as well use this system on a daily basis. So I decided to take the leap and use FreeBSD on my laptop (ThinkPad X201). I first installed FreeBSD 10 (RELEASE), but it didn’t work as expected. In particular the Intel KMS driver did not work properly. Also xrandr did not work, and the performances were far lower than Linux. Needless to say, I was a bit downhearted. I expected so much from this first installation.

After an evening weighting the pros and cons, sadly contemplating the idea of returning to Linux, I decided to give it another try with FreeBSD 11 (CURRENT). Fortunately almost everything worked perfectly then. The Intel KMS driver works, although I don’t have access to the ttys (ttys and suspend now work on HEAD). Xrandr works perfectly which is imperative to give a presentation. The wireless card, sound card, fingerprint reader and ultra base also work with no apparent problem.

However I still have some problems with the function keys not detected on the external ThinkPad keyboard. Also xscreensaver does not always detect the finger print reader. Finally the secondary mouse and keyboard are not always properly detected by X. I guess this is probably a problem with HAL. But I did not look into it yet (ums_load="YES" in /boot/loader.conf).

I did several quick benchmarks to compare the performances with the Debian installation. I will post the results in a few days. I will also leverage the change to update some of my projects and also to clean my configurations a little bit. I already did so for Emacs and Awesome WM, though for now I’ve something else to do.

Source based routing

My two home servers are down for the moment. This also means that our two IPv6 SixXS tunnels are down which costs us 100 ISK per week. Argh! I need to get these up and running as soon as possible. Fortunately we have another VPS on Linux that can save us. So we just have to enable the two tunnels there and make sure that we can ping to/from both interfaces.

Setting up the two tunnels is easy. Use one configuration file per tunnel. Ensure that you change the parameters “tunnel_id” to the tunnel associated to this configuration file, one “pidfile” and “ipv6_interface” for each tunnel and “defaultroute” to false because we already have a default IPv6 route. Now you can start/stop each tunnel with:

aiccu start /etc/aiccu/tunnel0.conf
aiccu start /etc/aiccu/tunnel1.conf

aiccu stop  /etc/aiccu/tunnel0.conf
aiccu stop  /etc/aiccu/tunnel1.conf

Don’t forget to hack /etc/init.d/aiccu to start/stop both tunnel on each reboot. OK! So now ifconfig list the two interfaces, up and running sixxs0 and sixxs1. This is great but wait… Nobody outside can ping these interfaces. The tunnel must ping to be considered active by SixXS so we better get this running.

For now we have these three interfaces and IPs (not the actual names/IPs):

  1. net0 (2001::1) default
  2. sixxs0 (2a02::1)
  3. sixxs1 (2a02::2)

By default, all our IPv6 traffic goes through net0. However and unsurprisingly our ISP filters the traffic at the output of net0. So we cannot use this interface to answer the echo-requests. Actually, what we want is that traffic originating 2a02::1 goes through sixxs0 and from 2a02::2 goes through sixxs1. That is, one default route based on the source address.

Linux has long had support for multiple routing tables (CONFIG_IP_MULTIPLE_TABLES). Basically what we will do here:

  • Create two routing tables for each tunnel interface (sixxs0, sixxs1).
  • Each table will have a default route through its interface.
  • Lookup into one of the two tables according to the source IP.

You can find some relevant documentation in Linux Advanced Routing & Traffic Control, Chapter 4.

We first list the actual rules:

# ip rule list
0:  from all lookup local
32766:  from all lookup main
32767:  from all lookup default

We can see that we have three routing tables. One for the local addresses, the normal routing table (what you get with ip -6 route) and the fallback default table.
Let’s first check the local routing table (we are just curious):

# ip -6 route list table local
local ::1 via :: dev lo  proto none  metric 0  mtu 16436 advmss 16376 hoplimit 0
local 2a02::1 via :: dev lo  proto none  metric 0  mtu 16436 advmss 16376 hoplimit 0
local 2001::1 via :: dev lo  proto none  metric 0  mtu 16436 rtt 6ms rttvar 7ms cwnd 10 advmss 16376 hoplimit 0
local 2a02::2 via :: dev lo  proto none  metric 0  mtu 16436 advmss 16376 hoplimit 0
local fe80::1 via :: dev lo  proto none  metric 0  mtu 16436 advmss 16376 hoplimit 0
local fe80::2 via :: dev lo  proto none  metric 0  mtu 16436 advmss 16376 hoplimit 0
ff00::/8 dev net0  metric 256  mtu 1500 advmss 1440 hoplimit 0
ff00::/8 dev sixxs1  metric 256  mtu 1280 advmss 1220 hoplimit 0
ff00::/8 dev sixxs0  metric 256  mtu 1280 advmss 1220 hoplimit 0

So now you know what’s going on when you ping one of your local interfaces. But back to our point. We name our two new routing tables in /etc/iproute2/rt_tables:

# SixXS tables
200 sixxs0
201 sixxs1

Now we add the default route in each of these two tables:

ip -6 route add default dev sixxs0 table sixxs0
ip -6 route add default dev sixxs1 table sixxs1

And finally we use two rules to map the source address to the correct routing table:

# ip -6 rule add from 2a02::1 table sixxs0
# ip -6 rule add from 2a02::2 table sixxs1
# ip -6 rule list
0:  from all lookup local
16383:  from 2a02::1 lookup sixxs0
16383:  from 2a02::2 lookup sixxs1
32766:  from all lookup main
32767:  from all lookup default

It should be OK but let’s check that. We can ping from the sixxs interfaces:

ping6 -c1 -I 2a02::1 www.kame.net
ping6 -c1 -I 2a02::2 www.kame.net

We also check that we can ping our interfaces from another host:

ping6 -c1 2a02::1
ping6 -c1 2a02::2

Everything works, that’s great! Finally we just hack /etc/init.d/aiccu to configure the routing tables on each reboot. Note that you need to sleep a bit when you issue the aiccu start because the daemon needs a bit of time to enable the tunnels. Also note that you must be careful when you test your script (quoting the SixXS FAQ):

“If a client connects more than 4 times in 60 seconds (1 minute) the client will not be allowed to connect again for the next 5 minutes. In case this threshold is exceeded more than once in 24 hours a client will be automatically blocked for a week.”

As you can guess, I have been blocked. Oops!

Chromium won’t start

Since several weeks now I had a problem with chromium. The web browser segfaulted on launch until I ran xfsettings. This daemon configures desktop settings for the xfce desktop. It listens to xfconf and uses the xsettings protocol to propagate configuration changes on-the-fly. So you can use xfce4-settings-manager and rely on the xfce configuration mechanism to change your desktop settings nicely. Actually I used that to easily change the GTK and icon themes.

This is great for fully integrated desktop environment as it gives you a shiny graphical interface that “just works”. However it doesn’t work so much when you modify much of your configuration by hand.

For example, I use a script which listens to changes in the VGA output port and uses xrandr to setup the screen accordingly. But no matter what, if I start xfsettingsd after the initial configuration, it resets everything to whatever xfce thinks my screen configuration should be. And since I didn’t told him, it has no clue. The same apply for the keyboard, for which I use the device name to select the layout (dvorak/azerty/qwerty). The daemon just resets the layout, and worst of all, enables numlock. But again, it has no clue.

So I decided not to use xfsettings anymore. But as soon as I did that, the chromium web browser did not want to start. It even segfaulted, which is bad, but anyway. I guess the problem was a misconfigured gtkrc (well… xfce wasn’t there to hold my hand anymore) which for some reason made chromium go completely nuts. So I fixed this by using LXAppearance to generate a more complete gtkrc which I modified by hand aftewards.

In fact, the actual problem was the gtk-font-name that missed an explicit font family. In other words, in my gtkrc,  I had this:

gtk-font-name="8"

Which I changed to this:

gtk-font-name="Droid Sans 8"

Why code In C anymore?

Quote

“Also, because it makes you a Real Man™, with steel wool-like hair on your chest and a distant gaze, as though contemplating the segfault that got away; UNIX beard moving gently in the harsh nautical wind that is ever present near C programmers.

The reason C is pronounced “sea” is because it refers to the sea of tears of quiche eating inferior programers who got too close to a programming language for Real Men™, and got burned, swearing to never leave the comfort of the namby pamby interpreted language that nutured them as wee latte-drinking babes with scarves.” [BobTheSCV (Reddit)]

SANE USB permissions

Today I had a permission problem with SANE on Linux. SANE stands for “Scanner Access Now Easy”, it provides standardized access to scanner hardware (http://www.sane-project.org) and this is the most commonly used scanning tool on UNIX/Linux.

In my case the USB scanner was not recognized when issuing scanimage -L from my user account although it worked correctly under root and my user is in the scanner group. What more is sane-find-scanner reported permissions errors while running the command as user. The owner and group for the device (in my case it was /dev/bus/usb/002/004) were root:root. At this point we already know that something weird is happening and I expected something like root:scanner instead.

Looking into /lib/udev/rules.d/60-libsane.rules, the line in charge of changing the permissions for each scanner device matched by SANE:

ENV{libsane_matched}=="yes", RUN+="/bin/setfacl -m g:scanner:rw $env{DEVNAME}"

This is nice but I do not use ACL and they are disabled in kernel,  so this command is useless. So I replaced this line with:

ENV{libsane_matched}=="yes", RUN+="/bin/setfacl -m g:scanner:rw $env{DEVNAME}", MODE="0664", GROUP="scanner"

Now the owner and group are correctly set to root:scanner and I can use my scanner as a regular user.

Note that on my system the libsane, sane-utils and xsane are the only packages depending on the acl package. According to what I’ve seen in the ChangeLog they do so in order to cope with MFP which I presume should be accessible as a scanner and printer device at the same time. What I would have done instead would be to create special group for MFP devices and use this instead. IMO still less of a mess than enabling ACL on the whole system for a single package.

GTalk browser plugin on Debian (testing)

So you installed the GTalk browser plugin on Debian testing and it doesn’t work. However GTalk is listed correctly when you list the plugins in your browser. So what now?

Well you can try to remove libudev0. It seems that the plugin has some problems when both libudev1 and libudev0 are present on the system.

Get rid of SIGINT

Yesterday I had some problems trying to get rid of the SIGINT signal (when you press C-c on your terminal). Imagine you have the following script :

# a.sh

b &
sleep

Let’s suppose that b is a sleep or another simple command or a shell script. In that case a SIGINT on the terminal will kill a.sh but b will be rattached to init. This is strange because:

  1. b effectively receives the signal (seen with strace)
  2. the default action should terminate the process
The reason behind this is that the shell will (roughly) do the following sequence of operations before starting the process in the background:
if(!fork()) {
  /* child */
  signal(SIGINT, SIG_IGN);
  signal(SIGQUIT, SIG_IGN);

  execve(...cmd...);
}

 

The execve manpage has this to say about signals:

*  POSIX.1-2001 specifies that the dispositions of any signals that are
ignored or set to the default are  left  unchanged.

i.e. the process will inherit SIG_IGN signals and set all the others to default. So with our shell the SIGINT is ignored for the background processes. However if the process defines its own handler and catch the signal, it will override the inherited SIG_IGN value. This is the case for example with tcpdump which will catch this signal to terminate properly. This is also the case for the following code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

void sigint(int n)
{
  printf("child int; exitn");
  exit(0);
}

int main()
{
  signal(SIGINT, sigint);
  usleep(-1);
}

In this case the process will catch SIGINT and terminate. So if we cannot prevent the process to catch the signal the question now is: How can we prevent b to receive the signal?

When this signal is generated, it is sent to the foreground process group on the session associated to the tty. If you have a shell open on your tty, it will be the currently running command if any. In this case the current command is a non-interactive shell script. In this non-interactive shell, all commands even those sent to background with “&” are attached to the same process group. So here the background commands of the shell script are associated to the foreground process group.  This is why they still receive SIGINT even when the parent process die and they are rattached to init.

The solution is to create the processes which we want to make unaware of SIGINT in a new process group, different from the foreground process group and therefore a background process group. However there is no command to start something in a new process group. Instead we have a command which can start something in a new session and therefore a new process group too. Better still, your process is detached from your tty which makes it (nearly) a real daemon. So the solution is:

# a.sh

setsid b &
sleep

Another solution forces the shell to turn on job control in non-interactive mode with set -m. This way each background process will be created in a new process group. This could be embarrassing though because you cannot background processes in the same process group anymore. Basically we want processes in the same process group to make sure that a SIGINT will terminate the entire script, background commands included. Otherwise you have to save the pid, trap the SIGINT signal and take care of terminating everything by yourself.

Moreover using setsid is a part of the REAL answer to this question:

“How do we fully detach a process from its tty?”

For which we almost see:

“Use nohup…”

Which is wrong! According to man nohup justs: “run a command immune to hangups, with output to a non-tty”. That is, it will just adjust input/output, ignore SIGHUP and exec your command. However if you do something like signal(SIGHUP, SIG_DFL); then nohup has no effect anymore and the process will be terminated when the terminal hang up.