Planet FreeBSD

January 18, 2022

Adrian Chadd

Figuring out how Amiga 500 RAM expansion projects work

 (Wow, what a shift in topics here..)

Yeah I picked up an Amiga 500. Specifically, a rev6 amiga 500. It has 4 extra spots on the mainboard for another 512k of chip ram that isn't populated.

Crap I'm going to have to explain chip RAM.

Ok, so the Amiga is a pretty nifty architecture, especially if you realise it was designed in the early 80s. I won't go into it all because that's not the point of the article and that's covered on the internet.

What I will go into is what I've figured out with the RAM expansions.

So - the RAM types. This is the bits I knew back as a teenager.

The Amiga has three kinds of RAM:

  • Fast RAM is RAM that the CPU can see, but the custom chipsets can't address. It's not slowed down by any contention with the chipset access to its RAM.
  • Chip RAM is RAM that the CPU and the custom chipsets can see. This RAM sits /behind/ the custom chipsets; access to it from the CPU is lower priority than from said chipsets.
  • Slow RAM is RAM that also sits behind the custom chipsets, but for reasons internal to said chipsets they can't actively use. If the custom chipsets are using chip RAM for functions then the CPU will also be blocked.

The reason for chip/slow RAM on the early Amigas only makes sense if you peer into Agnus, the DMA and RAM arbiter chipset. It has a variety of features, but it's basically a big RAM arbiter and DMA engine. The earliest version in the Amiga 1000 supported DMAing to/from 512KB of RAM. However, it supports controlling 1MB of RAM. The next major version update (which I have) supports DMA from and to 1MB of RAM.

Now, because of this early limitation, the Amiga designers put the first 512k that Agnus can control early in the memory map (at $000000), and moved that second 512k of RAM much later in the memory map (address $C00000). That way a future chip that supported more DMA accessible RAM would just extend the chip RAM memory map in a contiguous fashion.

However, this meant a bunch of software was written that assumes the first 512k is at $000000 and the second 512K is at $C00000. Not a lot, but some.

My goal is to have 1MB of chip RAM and at least 512k of slow RAM. That should give the maximum compatibility with all of the Amiga 500 software in the past and set things up pretty well for the future.

Now, this is something people have already done. PeteAU on the Amiga Forums kickstarted a bunch of designs which were debugged and improved upon by forum members. Let's talk about how it works.

First up, Agnus decodes a bunch of address lines to know what the CPU is requesting. However, it only treats things as a memory access if Gary, another custom chip, decoded the address bus and said "yup, this is a RAM access." Gary asserts /RAMEN to Agnus to let Agnus know it's a RAM access and Agnus takes care of doing the memory transfer.

JP2 on the Amiga 500 rev6 board chooses whether Agnus sees the CPU A19 line as A19 or A23. If it's A23, the default, then the second half of Agnus' address bus as viewed by the CPU is at the slow RAM address of $C00000. But if JP2 is cut and the other link is joined, it becomes A19 and both 512KB RAM blocks show up as contiguous RAM at $000000, as chip RAM.

Agnus decodes its A19 line to select which of two 512KB RAM blocks to enable. It does this using the /RAS0 and /RAS1 lines. /RAS0 enables the onboard 512KB RAM. /RAS1 enables the unpopulated 512KB RAM chips on the mainboard. Also, BOTH /RAS0 and /RAS1 appear at the trapdoor RAM expansion underneath the Amiga 500, and the Amiga 501 512KB RAM expansion uses /RAS1 by default.

So, you can easily choose between 1MB of chip RAM and a 512KB chip/512KB slow by changing JP2. That's easy.

JP7 controls whether Gary sees the /EXRAM line from the trapdoor expansion. Gary uses this to control which address ranges are treated as RAM and sent as an enable line to Agnus via /RAMEN.

JP3 controls which 512KB bank is /RAS0 or /RAS1. It lets you swap them, so the trapdoor RAM and onboard RAM sees /RAS0 as /RAS1 and vice versa. You normally shouldn't have to fiddle with this.

Finally, Agnus is responsible for managing the DRAM chips. This requires:

  • Managing the multiplexed column/row address bus setup that DRAM chips use, so it has to latch rows and then columns for reading
  • Asserting the right /RAS and /CAS lines to the right chips (important for normal AND RAM expansion hacks!)
  • Handling DRAM refresh.

Ok, so now that this is done, let's talk about PeteAU's RAM expansion and how they managed to get 1MB of chip RAM and lots of slow RAM.

There are two halves - the expansion RAM board and the "Gary adapter". The easiest to talk about is the expansion RAM board, so that goes first.

The RAM expansion boards still take /RAS0 and /RAS1, and provide jumpers to which ends up at which RAM. Ok, so how does it actually enable different RAM banks?

The two wires that go to the RAM expansion boards are either A19/A20 or some decoded magic that I'll describe later. These feed into a 74LS139 which is a dual 2-to-4 demux. Each demux is responsible - this is important - for demuxing the /CAS lines. So yes, even if all the expansion RAM is using /RAS1, the /CAS lines get enabled only for the RAM that matters. It's important to understand this particular bit of magic. Agnus only has two /CAS lines - one for the lower 8 bits and one for the upper 8 bits of the 16 bit data bus. So all of the RAM gets /CAS enabled, no matter which 512KB bank it is - then the relevant bank to read gets /RAS. Now with PeteAU's design the /CAS lines for the relevant expansion bank gets enabled.

Ok, this is where it gets hairy. So, what about if you have 1MB of chip RAM on board, like I do? PeteAU's Gary board apparently takes care of that too.

One final comment before I move onto the Gary adapter board. Why not go and fiddle with /RAS to enable the right banks? Well, it has to do with DRAM refresh. Agnus also takes care of the refresh cycles which involves asserting only /RAS and enabling each row in the DRAM. If we go and gate which /RAS goes to which chip bank then a bunch of RAM won't get refreshed. You'd then have to add extra logic to see if it's a refresh cycle and manually refresh! Or, you can leave /RAS0 and /RAS1 alone, so DRAM refresh is still OK, and enable RAM using /CAS.

Right! Now onto the Gary board, where the magic happens.

A few things have to happen here for all of this magic to be, well, magic.

  • If you want to support 1MB chip RAM as well as 512K of slow RAM, you need to be able to decode both the chip RAM and slow RAM regions and enable those to Agnus via its A19 line. This is the jumper wire to JP2 on the A500 Rev6 PCB.
  • If you want to support more than 512K of slow RAM, you need to decode both A19 and A20 and fake the /REGEN and /RAMEN signals towards Agnus. (/REGEN is "chipset register space is being accessed.) That way Agnus still thinks a RAM cycle is being initiated, even if it can't "see" the larger RAM address space.
  • Then you need A19/A20 - or a modified version - to the trapdoor RAM expansion. This is the extra 2 bits, or 4 banks of 512KB, to decode all that extra RAM.
  • If Agnus is asserting /BLIT - which says it's doing a DMA cycle, then we need to ensure it's going to U1 on the RAM expansion, or the second 512KB chip RAM bank.

Now, this last point is important for me and other 1MB Amiga chip RAM amiga 500s. How can this RAM expansion even work if there is 1MB of chip RAM on-board? The on-board RAM has all of the /CAS lines from Agnus wired up, without going through the mux.

I think the answer is "not without modifying the board." /RAS0 will continue to enable the first 512K bank. The other 512KB bank and the slow RAM expansion will run off of /RAS1. What I'm likely going to have to do is:

  • Build a 74LS139 adapter board myself for the mainboard;
    • Run the /CAS lines from the expansion connector to it;
    • Run the Gary expansion adapter A19/A20 lines to it;
  • Lift the /CAS lines from the other 512KB RAM I installed, and route it to the 74LS139, like what PeteAU's RAM expansion board does;
  • Modify my A501 (that should be here soon!) to use the /CAS lines I feed it from the 74LS139 board, rather than the expansion connector /CAS lines;
  • Hope it all works!

I'll try to remember to report back with some photos!


by Adrian ( at January 18, 2022 05:56 PM

December 14, 2021


Secure Containerized Browser

By default Chromium on OpenBSD (not so) recently got OpenBSD’s unveil(2) support. That means that of you run Chromium with --enable-unveil flag then it will be prevented from accessing anything other than the ~/Downloads directory. No such thing on FreeBSD exists. Firefox or Chromium have access to all files user can read – even to your system sshd(8) keys or even worse to your private keys laying in the ~/.ssh dir. On FreeBSD thanks to its FreeBSD Jails technology we can create secure containerized browser with only access to the specified directory. On my system its the ~/download dir.

You may want to check other desktop related articles in the FreeBSD Desktop series on the FreeBSD Desktop page.


We will start with /etc/jail.conf file configuration. For the record – we will be using /jail for our FreeBSD Jails main dir. I will also use /jail dir for the ‘base’ FreeBSD versions tarballs as a convenient place. As I use address space I will use for our containerized browser. Feel free to pick other IP from which you will be able to reach the Internet. The /etc/jail.conf is shown below. One thing to note here. As I am using WiFi wlan0 interface I have put that into the Jail configuration. If you use LAN interface (for example em0) then put that instead into this Jail config. As you see from the example below we will be using Firefox browser in out example.

root@host # cat /etc/jail.conf

  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_${name}_console.log";
  host.hostname = ${name};
  path = /jail/${name};

  firefox {
    devfs_ruleset = 30;
    ip4.addr =;
    interface = wlan0;
    mount.fstab = "/jail/firefox/etc/fstab";

As you can see we will also be using devfs(8) rules in the /etc/devfs.rules file – shown below. This configuration is needed to have access to sound(4) in our FreeBSD Jail. If you do not need sound then you can delete devfs_ruleset = 30; from the /etc/jail.conf file and also do not add anything in the /etc/devfs.rules file.

root@host # cat /etc/devfs.rules
add path 'mixer*' unhide
add path 'dsp*'   unhide

If we are about to share the ~/download dir with our containerized browser then we need to somehow add that information to our FreeBSD Jail. We will use the FreeBSD’s mount_nullfs(8) command to mount our currently existing ~/download dir into our FreeBSD Jail. We will use following /jail/firefox/etc/fstab for that purpose.

root@host # cat /jail/firefox/etc/fstab
#SOURCE         #MNT                                      #TYPE   #OPTS       #DUMP/PASS
/data/download  /jail/firefox/usr/home/vermaden/download  nullfs  rw,noatime  0 0

Of course you do not have to share any directory with your containerized browser.

You may as well would want to make this jails start everytime you boot your system. To do that add below lines to the /etc/rc.conf file as shown below.


Create the Jail

As I use FreeBSD 13.0-RELEASE I would be using also the FreeBSD 13.0-RELEASE Jail for that purpose. If you are running for example FreeBSD 12.3-RELEASE then make sure that you will use FreeBSD 12.3-RELEASE Jail. The Jail version needs to be lower then the host system version. We will now fetch needed FreeBSD ‘base’ file and unpack it within /jail/firefox dir where our container would live. We will also configure several other basic files such as /etc/resolv.conf or /etc/hosts files.

root@host # mkdir -p /jail/BASE /jail/firefox /jail/firefox/usr/home/vermaden/download

root@host # fetch -o /jail/BASE/13.0-RELEASE-base.txz \

root@host # tar -xvpf /jail/BASE/13.0-RELEASE-base.txz -C /jail/firefox

root@host # echo nameserver > /jail/firefox/etc/resolv.conf

root@host # echo firefox >> /jail/firefox/etc/hosts

root@host # cat << EOF > /jail/firefox/etc/fstab
#SOURCE         #MNT                                      #TYPE   #OPTS       #DUMP/PASS
/data/download  /jail/firefox/usr/home/vermaden/download  nullfs  rw,noatime  0 0

We will now start our fresh FreeBSD Jail.

root@host # service jail onestart firefox

We can now also see two new mounts in the mount(8) output.

root@host # mount | tail -2
/data/download on /jail/firefox/usr/home/vermaden/download (nullfs, local, noatime)
devfs on /jail/firefox/dev (devfs)

root@host # mount -p | tail -2 | column -t
/data/download /jail/firefox/usr/home/vermaden/download nullfs rw,noatime 0 0
devfs /jail/firefox/dev devfs rw 0 0

You may want to update the FreeBSD version to the most up to date one with freebsd-update(8) commands.

root@host # freebsd-update -b /jail/firefox fetch
root@host # freebsd-update -b /jail/firefox install

Install Needed Packages

Before installing anything we will first switch to the latest branch for the pkg(8) packages to have most up to date software. We will then process to installing the Firefox package. We will also need x11/xauth package for X11 Forwarding process.

root@host # sed -i '' s.quarterly.latest.g /jail/firefox/etc/pkg/FreeBSD.conf

root@host # grep latest /jail/firefox/etc/pkg/FreeBSD.conf
  url: "pkg+${ABI}/latest",

root@host # jls
   JID  IP Address      Hostname                      Path
     1      firefox                       /jail/firefox

root@host # jexec 1

(root@jail) # pkg install -y firefox xauth

Create Matching User and Configure sshd(8) Daemon

We will now enter our FreeBSD Jail again for several other needed tasks for our containerized browser to be working. First is creating inside similar user as you currently use inside. Especially with the same UID/GID to have files with proper permissions in your real ~/download directory instead of files with other UID/GID that you will have to chown(8) with root user. As my vermaden user uses UID/GID 1000 I will also use that inside. I will also set simple password that You will only use once – to copy your public SSH key there.

root@host # jexec 1

(root@jail) # echo your-username-password-goes-here | pw user add -u 1000 -n vermaden -m -s /bin/sh -h 0

Now we need to run /usr/local/bin/dbus-uuidgen --ensure once to make sure DBUS is initialized properly. Firefox and many other apps would not start if we omit that step.

(root@jail) # /usr/local/bin/dbus-uuidgen --ensure

Now the sshd(8) daemon. The only thing we need to do is to add it to the system startup and also add X11UseLocalhost no option to its config file.

(root@jail) # sysrc sshd_enable=YES
sshd_enable: NO -> YES

(root@jail) # echo X11UseLocalhost no >> /etc/ssh/sshd_config

(root@jail) # service sshd start
Generating RSA host key.
2048 SHA256:VnrvItf0tl738C5Oc2St6T63/6o8zaDlfUskB+NrElo root@firefox (RSA)
Generating ECDSA host key.
256 SHA256:ZAjcAGqlrVwvY+J9MuVzErx9QUOqIOJE3nJX/Oqwtpk root@firefox (ECDSA)
Generating ED25519 host key.
256 SHA256:JdzUql2D2+X8iBn3c1jWDHQRNQMKqWGOcL4J16fIX0E root@firefox (ED25519)
Performing sanity check on sshd configuration.
Starting sshd.

Copy Public SSH Key and Start

Copying your public SSH key is optional but if you omit this step then you would have to type your FreeBSD Jail user password every time you would want to start your secure Firefox instance.

vermaden@host % ssh-copy-id -i ~/.ssh/id_rsa vermaden@

Now you can start your containerized browser. I have added some useful flags for ssh(1) client like compression with -C and fastest supported encryption with -c aes128-ctr option. The -X is for X11 Forwarding option. I also added GDK_SYNCHRONIZE=1 to make Firefox yell less 🙂

vermaden@host % ssh -C -c aes128-ctr -X vermaden@ env GDK_SYNCHRONIZE=1 firefox --new-instance

Now without password you should see fresh Firefox instance.


I will now try to play some random video. I can not show you that from an image but the sound also works 🙂


Similar setup can be created for other browser if Firefox is not your browser of choice of course. If you are curious how much space it uses its about this:

root@host # du -smx /jail/BASE/13.0-RELEASE-base.txz /jail/firefox 
181 /jail/BASE/13.0-RELEASE-base.txz
1603 /jail/firefox

root@host # du -smx -A /jail/BASE/13.0-RELEASE-base.txz /jail/firefox
181 /jail/BASE/13.0-RELEASE-base.txz
2601 /jail/firefox

I also added the -A flag in second the du(1) command to show you how much more space would be used without the ZFS LZ4 compression.

UPDATE 1 – Use XPRA Instead of X11 Forwarding

Some people complained that this is quite good setup but they were not happy with using X11 Forwarding for the connection method. I decided to add additional XPRA method to connect to our secure containerized browser. First thing you need to do is to install the x11/xpra package on both the host system and also inside the jail container.

root@host # pkg install -y xpra
(root@jail) # pkg install -y xpra

Now – after logging into your user in the Jail container – vermaden in may case – we will use the xpra commands to create new session with Firefox browser.

Lets see if any xpra sessions currently exists.

(vermaden@jail) % xpra list
Warning: XDG_RUNTIME_DIR is not defined
 and '/run/user/1000' does not exist
 using '/tmp'
No xpra sessions found

Seems not. We can not start our Firefox session.

(vermaden@jail) % xpra start --bind-tcp=:14500 --start='firefox --new-instance'
Warning: XDG_RUNTIME_DIR is not defined
 and '/run/user/1000' does not exist
 using '/tmp'
Entering daemon mode; any further errors will be reported to:
Actual display used: :0
Actual log file name is now: /tmp/xpra/:0.log

We can see in the xpra list command that new session appeared.

(vermaden@jail) % xpra list
Warning: XDG_RUNTIME_DIR is not defined
 and '/run/user/1000' does not exist
 using '/tmp'
Found the following xpra sessions:
        LIVE session at :0

We can also see that xpra is now listening on the 14500 port.

(vermaden@jail) % sockstat -l4
vermaden python3.8  20781 3  tcp4      *:*
root     sshd       58454 3  tcp4         *:*
root     syslogd    48568 5  udp4        *:*

We will now move to out host and start graphical xpra client to connect to our FreeBSD Jail with Firefox process.


After clicking the large Connect button we can now enter our Jail address.


After again clicking the Connect button on the bottom this time we can now se our Firefox browser from our secure environment.


After we done our job at more secure Firefox we can now end our xpra session on the jail system.

(vermaden@jail) % xpra stop
Warning: XDG_RUNTIME_DIR is not defined
 and '/run/user/1000' does not exist
 using '/tmp'
xpra initialization error:
 cannot find any live servers to connect to

(vermaden@jail) % xpra list
Warning: XDG_RUNTIME_DIR is not defined
 and '/run/user/1000' does not exist
 using '/tmp'
No xpra sessions found

As XPRA provides OpenGL acceleration you may verify that fact from your host system using below command.

vermaden@host % xpra opengl
Warning: XDG_RUNTIME_DIR is not defined
 and '/run/user/1000' does not exist
 using '/tmp'
Warning: cannot handle window transparency
 screen is not composited
Warning: vendor 'Intel Open Source Technology Center' is greylisted,
 you may want to turn off OpenGL if you encounter bugs
Warning: window 0xffffffff changed its transparency attribute
 from False to True, behaviour is undefined
display_mode=ALPHA, DOUBLE
max-viewport-dims=16384, 16384
renderer=Mesa DRI Intel(R) HD Graphics 3000 (SNB GT2)
vendor=Intel Open Source Technology Center

You can also use VNC or other methods of course.

Hope that helps 🙂


by vermaden at December 14, 2021 11:09 PM

November 09, 2021


UNIX Mouse Shootout

While most hardcore UNIX users prefer keyboard shortcuts over anything else – and I often align with that view – I really do appreciate good mouse on my UNIX system. In the end its close to impossible to edit images in GIMP without mouse for example. This ‘shootout’ will definitely be subjective as it will be limited only to mice that I own(ed). I will not bore you with all the technical specifications of these devices – you can check them on your own.

Besides – UNIX has two copy/paste buffers instead of just one like in most systems. There is PRIMARY and SECONDARY buffers in X11 for mouse. One is used when you use Copy/Paste options from menus and/or keyboard shortcuts like [CTRL]+[C] and [CTRL]+[V] ones. The other one is used when you just SELECT the text. After releasing the left mouse button (and finishing the selection) you have that text stored in your SECONDARY buffer. You may now paste that with pressing the third/middle mouse button. But the PRIMARY buffer did not changed during that operation so you can also paste the other text you had in your PRIMARY buffer from the earlier [CTRL]+[C] operation. This makes mouse on UNIX more useful – definitely bigger then in other systems.

While Bluetooth is widely used on most mobile phones/tables and even cars now I do not find it desired as the only protocol for the mouse. I do not have anything against it when it comes as an additional possibility like with the Logitech M720 Triathlon mouse – its even nice that way – but I would not use mouse that the only possible way to connect/operate is by Bluetooth protocol. Maybe on a macOS UNIX but definitely not on FreeBSD UNIX 🙂

AMIGA ‘Tank’ Mouse

The first mouse device that I used was the oldschool AMIGA ‘Tank’ Mouse which I used alongside my first computer – AMIGA A600. When I used it or played Cannon Fodder it felt more then up to the task but using only two buttons mouse (without any scroll and third button) in 2021 feels almost impossible for me.


It was possible to run AMIGA UNIX (also known as Amix) on AMIGA hardware. That was an AT&T Unix System V Release 4 developed as alternative to default AmigaOS but you needed Amiga A3000UX hardware for that.


Unfortunately the AMIGA A600 was not supported 😦

Lenovo and ThinkPad Twins

One of my older/earlier mouse models that I used were quite ‘identical’ mouse models Lenovo Wireless USB Mouse (0A36188) and ThinkPad Wireless USB Mouse (0A36193) – both made by Lenovo for the record. They have the same size and work mostly the same but the older one – ThinkPad model (0A36193) – had more responsive third button (the one under the wheel) – the Lenovo (0A36188) kinda needed real strength to press it – that was its downside.


I still own the ThinkPad one (0A36193) and use it from time to time when I travel – the two AA batteries allow quite long operation of more then a month – which is more then enough for my standards.

Its my first mouse that got additional buttons on the scroll wheel for left and right operations – I used it for volume control on my UNIX system which was (and still is) VERY convenient.

While I really like its/their small size – but after some longer use I really miss some more ergonomic shape under my hand. That means that it ‘will do’ for short periods of usage in travel situations but for long work use something more ergonomic then these.

Logitech Marathon M705 (GEN 1)

I got it after more then a year of using Lenovo and ThinkPad mice. It was real upgrade with quite nice profiled shape to the right hand. It was also quite heavy – but that was good – it felt really good to operate in hand. It was branded as very long to use without changing or charging the batteries and it really did provided in that department – I needed to change/charge the batteries maybe once a year or less often. It was also more precise then simple ThinkPad/Lenovo mouse.


The volume buttons from the wheel that I used on the Lenovo and ThinkPad mice was not quite possible here. While the mouse have these left/right buttons on the wheel they were clumsy and not very precise – so you loss more time trying to press them properly then doing it the other way. With Logitech M705 I ‘moved’ my volume controls to other two buttons that were available under the thumb button. Fortunately there are two of those additional buttons so it was perfect for volume up and volume down actions.

This is also the first mouse that allowed to toggle the wheel to be ‘clickless’ – you can literally spin it for several seconds without any resistance – it just keeps rolling itself – and to be honest – that is one of the features I now DEMAND from any mouse. It makes life so much better (and faster). Instead of scrolling many – many times to get where its needed – you just spin it once and wait till you get there – and even a lot faster then with ‘traditional’ clicking mouse wheel.

Another advantage of that approach is that tip of your finger does not hurt after all day long of scrolling … and if you need precision clicking wheel – then just toggle it and you can click-scroll as usual.

With Logitech Marathon M705 mouse I also grow another ‘useful’ habit (or need) in a mouse. I started to use the lower thumb button to toggle between pause/play for my Deadbeef music player. Before that I used to switch to Workspace 3 where it plays music and press [C] key to toggle pause/play. After adding additional deadbeef --play-pause action to my xbindkeys(1) config now all I have to do to toggle between play and pause is to just push my thumb mouse button. Way faster 🙂

Logitech Performance MX

After reading many comparisons with Logitech MX Master generations I finally settled on the Logitech Performance MX mouse. It is really big and that is really big advantage. It handles/lies really nice in a hand and being quite large and heavy it is very precise and you got ‘good’ feeling and confidence of using it. I really liked it till I got to know its two big downsides … first was the battery time. I needed to change/charge battery about once a week. That was REALLY disappointing. The other downside was that it was not able to properly operate on a flat WOOD surface (like on the photo below). Plain simple flat wood. All other mice worked well on this surface while this one did not. The marketed Darkfield sensor was useless. These were the two reasons that I got rid of it.


Same as with M705 the left/right buttons on the wheel were not very precise so I used the additional thumb buttons for volume management. The Logitech Performance MX mouse also comes with micro USB port at the front so you may use the mouse while you are charging it. Its real pity that Logitech did not used two (or even three) AA batteries for this mouse to make it last longer … but that would not resolve the Darkfield sensor not able to cope with movement on the wood 🙂

Logitech Marathon M705 (GEN 2)

I have read a lot of hate and disappointment about the latest generation of Logitech Marathon M705 mouse. Also the lower thumb button is missing and currently it uses only one AA battery. It still provides very long time without the need to change/charge and its lighter now. Its neither bad nor good – its just different. The precision is similar but after using Logitech Performance MX you really miss that big size.


The second generation of M705 did not improved the left/right buttons on the wheel so I decided to stick with additional thumb buttons for volume management.

I also really missed that lower thumb button that is gone from the GEN 2 Logitech Marathon M705 mouse – needed to go back to my [C] routine …

Logitech Triathlon M720

I recently got the possibility to check and use the Logitech Triathlon M720 mouse and I must say that I am positively surprised. Its both Bluetooth and USB dongle mouse so you can choose which way you would like to connect it to your computers. The plural form is intended here as the Logitech M720 allows you to switch between 3 computers with additional dedicated button. It also got ‘back’ the lower thumb button that was missing on the latest generation of the Logitech M705 mouse. The light/white lower bottom of the mouse looks little strange though … but its kinda not visible when it is laying on the table.


The M720 has more precise left/right buttons on the wheel but I got so used to manage volume with my thumb that I currently keep these ‘wheel’ buttons unused.

Having the lower thumb button again I was also able to get back to my toggle play/pause Deadbeef operation. Yay!


I never owned Logitech MX Master mouse. I used version ‘3’ for short time as one of my buddies own it and it felt quite similar to Logitech Performance MX in operation but not quite the same. Similar but different. I think that it would be comfortable but not sure about the precision on wood and battery time. Maybe I will got it some day and add an update here.


… but given the fact that Logitech MX Master mouse also has micro USB port at its front for charging I would suspect that battery time is also not that great. Similarly like the Logitech Triathlon M720 it also allows to switch its presence between 3 computers. There is also additional wheel for vertical scrolling. Never used that but maybe it would be useful in GIMP for example.


So what does a good UNIX mouse feature? I would summarize all the needed (or at least useful) feats in a list below.

  • needs to be at lest a little ergonomic
  • allows to toggle wheel between click and clickless operation
  • have additional buttons for custom actions
  • allows more then one month of work on batteries
  • works on different surfaces without a problem
  • has a USB dongle so Bluetooth is not needed

What other features you desire in mouse? I also thought about ‘vertical’ mouse type/shape and also about trackball. I tried my neighbor Logitech trackball several times but I am not sure I would get used to it after so many years of ricing the mice 🙂

External Discussions


by vermaden at November 09, 2021 12:06 AM

October 02, 2021

Warner Losh

Spelling Fixes -- Some Advice

 Some Thoughts on Spelling Fixes

I've been looking at a number of FreeBSD pull requests lately. Many of them are spelling fixes. I'd like to offer some suggestions for people submitting them. The same advice applies to typo fixes and grammar corrections.

  1. Keep number of changes small.
  2. Use separate commits per directory
  3. Use descriptive commit messages
  4. Set your email correctly
  5. Don't correct code

Keep number of changes small

When submitting like this, limit the number of changes to 10-20. More than about 15 changes becomes hard to review. Every single change has to be verified for correctness, and having too many will make your pull request more likely to be overlooked.

Use separate commits per directory

When submitting a number of changes, do one change per subdirectory. When subdirectories are nested, it's OK. For example, if you have changes to bin/ls and bin/rm, do two commits. But if you have changes to both usr.sbin/wpa/wpa_priv and usr.sbin/wpa/wpa_cli, then it's OK to do those as one commit.

Use descriptive commit messages

The commit message "fix spelling" is too generic to be useful. If you are fixing just one word, a better commit message would be "Spell interrupt correctly". It also allows the reviewer to make sure that you are changing the right thing. And it also gives enough detail that people skimming the logs don't need to look at the diffs to know what changed. If you are fixing multiple spelling errors, then a generic message is more appropriate.

Set your email correctly

When you push your branch to github, make sure that you've set the email you want in the commit message. It saves a lot of time. If you are using github's editor, make sure that your profile has this information set correctly.

Don't correct code

Don't make spelling corrections in code variables, #defines, etc. These will likely be ignored. The risk from a comment or an error message being corrected is tiny, while code changes could be attempts to subtly change the system or introduce security impacting issues through a supply chain attack. It's better to work with someone in the community to get these corrected than to correct them via a pull request.

by Warner Losh ( at October 02, 2021 05:10 PM

August 31, 2021


HardenedBSD August 2021 Status Report

This month was spent in writing utilities and libraries for HardenedBSD's infrastructure. I wrote a little library, called liblattzfs, to help our infrastructure monitoring daemon (hbsdmon) monitor the various ZFS pools on our systems. Though liblattzfs is developed out-of-tree, I've already merged it into the source tree.

I also worked on another library, liblattutil, to make it so that our applications can have one centralized logging API. It also has a nifty SQLite3 wrapper. One could use this wrapper to convert a SQLite3 query's result to JSON. :-)

I created a new little application (rync) to convert our every-six-hour auto-sync scripts from csh to C.

I also disabled CFI for wpa_supplicant. It's my hope that one day, I/we finally get Cross-DSO CFI working in base so that we can re-add CFI to some of these applications. I'm hoping to get back to Cross-DSO CFI work in the coming week.

FreeBSD released some securty advisories, so I made sure that we had binary updates released in a timely fashion. The package builds are still running.

FreeBSD updated ports-mgmt/pkg from 1.16.3 to 1.17.1, introducing some major changes that caused issues with our package repo. It took me a few days to find and resolve the issues. If anyone else notices any issues with the package repo itself, please let me know.

Loic reported an issue with randompid calculation, so I fixed that. He also fixed a few ports and researched the failures of a few others.

Overall, August was a month spent on HardenedBSD's auxiliary applications with the goal of enhanced stability.


by Shawn Webb at August 31, 2021 02:20 PM

Colin Percival

FreeBSD/EC2 AMI Systems Manager Public Parameters

In June, I posted a EC2 Wishlist with three entries: "AWS Systems Manager Public Parameters", "BootMode=polyglot", and "Attaching multiple IAM Roles to an EC2 instance". I am happy to say that my first wish has been granted!

August 31, 2021 04:30 AM

August 28, 2021

Warner Losh

A new path: vm86-based venix emulator

 Venix Emulator Update

It's been a while since I've had time to work on the Venix emulator. When I set it aside over a year ago, I'd taken it as far as I could with the 8088 emulator I'd found online. It had no FP emulation and there were
a number of things misbehaving that I couldn't quite get right. And exec was proving hard to implement. Despite being written in C++, the original emulator resisted my efforts to make multiple instantiations.

So I set it aside last May, thinking I might get back to it when the qemu bsd-user changes FreeBSD has done have been upstreamed.

The first of August I took some time off from work and got the bsd-user changes in shape to upstream. Well, the first 10% of the changes that were the hardest since it was replacing what was there with something that minimally worked. This helped me learn qemu's x86 CPU much better and it got me thinking that qemu's user-mode stuff might be the way to go.

About this time I also found a vm86 test program in the FreeBSD tree. So I got to wondering, could I do a vm86 implementation of Venix?

So, I stole the bulk of my old 86sim-based Venix implementation, installed a i386 VM using bhyve on my FreeBSD/amd64 box and write a quick little test program. The test program worked, so in a fit of "why not give this a try" I ported the from 86sim to being driven from SIGSEGV in vm86 mode. Hello world quickly worked.


So, I reworked fork and exec and the a.out loader a bit. I was able to get the C compiler going in this new setup. The 'cc' command is just a fancy script that strings together the pre-processor, compiler, optimizer, assembler and linker. Except on Venix it wasn't a shell script I could hack to run natively on FreeBSD. It was this weird binary that did all the forking, execing, redirecting, etc inline. More on that in a minute.

So vm86 mode is a special mode in 32-bit CPUs that lets you execute old 16-bit code in the context of a normal process. It's super easy to setup, but often of limited use.

Thankfully, the i386 ELF designers thought ahead. The starting address for binaries in ELF is this weird 0x00401430, which is just above 4MB. This means that one can map anything into low memory and it will work. FreeBSD has a security stop on mapping anything at location 0, however, but the rest of the first 4MB is available. The old 8086 could only see the first 1MiB of that, but since Venix binaries are at worst 'small-mode' the largest address space for a process was 128kiB. Plenty of room to find a place to map it.

So, I wrote a loader that would load the old Venix a.out binaries into this space. Or rather I hacked the loader I already had to do the mapping. I was able to reuse all the loader code from the 86sim-based emulator I had before.

I then shamelessly stole the setup code from the FreeBSD vm86 testing binary, which was little more than establishing signal handlers and zeroing the context and setting up a stack and IP as well as the segment registers. With that in hand, I was able to use sigreturn() to set the processor flags such that it would jump to where I wanted to go in the Venix binary. I'd been afraid of vm86 mode after reading through doscmd years ago, but there was no need for the fear: all the cruft in doscmd (I reread it after this) was the accumulation of cruft over the years for DOS, BIOS and other weirdness that evolved around the IBM PC, XT, AT and the plethora of clones which had nothing to do with vm86 mode, per se.

Every INT xx instruction would trap to the kernel. The kernel would note down the registers and send the process a SIGSEGV for these accesses. I was able to then look at CS:IP in the mcontext and decode the instruction that faulted. INT xx is encoded as the bytes 0xCD 0xXX for almost all values of X (INT3 has its own opcode 0xCC). In the signal handler, I could decode this opcode. I knew from past work that INT 0xf1 was the system call, so I hooked up the old venix system call handlers to this and I was back to where I was with 86sim. Further in fact because floating point worked.

Signal handlers have an implicit sigreturn with the context passed to the signal handler at the end. I needed to skip over the faulting instruction after performing the system call, and the process would then resume executing in 16-bit mode after the INT 0xf1. This was straight forward to implement.

I decided to implement fork as a real fork. It would copy the address space, all the open FDs, etc. This proved to be an easy way to cheat so I didn't have to create a context object and use threads to simulate processes.

Exec proved to be just a call to my loader that started all this off. The only thing I've not implemented is close on exec, but the rest was easy.

With these implemented, I could run the C compiler's cc command and generate trivial binaries. But if I needed to include anything, it would fail. I created a VENIX_ROOT env variable. For all opens, it would try VENIX_ROOT / name and then just the plain name if the name arg to open started with a '/'. This was enough for the preprocessor to include .h files and for the canonical hello world to build.

There was just one vexing problem: cc -o hello hello.c worked. However cc -O -o hello hello.c didn't.

Tracking down a silly bug

Well, there was another annoying thing: /bin/sh didn't work. I traced that to the fact I've not implemented passing an environment to the processes, and /bin/sh was choking on that. OK. Fine. I'll implement that later. /bin/csh worked, however, so I was happy. My happiness was short lived, alas, because I'd run a  command and I'd get weird output:
% ls
ls: Sig 44

 That's weird. So I added tracing. I tried the cc command, which in this version is a simple program that orchestrates all the different parts of the compiler using fork, exec, dup and the strategic close/open pair to setup stdin etc. All the tracing looked good as well, we'd see something like:

123: fork() 124
123: wait()
124: ... lots of stuff
124: exit 0
123: wait pid 124 status 0

 and then 123 would proceed to delete all the temp files and exit. It was like it was getting an error, despite its children exiting without an error. Every time it was like this, but only when I ran the optimizer. When I'd re-run the ls test, I'd get different Sig values as well.

Available 8086 compilers in 1985

So, I'd assumed that the compiler was derived from the V7 compiler. However, a number of hints in names suggested it wasn't. And the Venix manual had way more exceptions for 8086 than for pdp-11 when it described the options and operation for Intel, so I assumed it wasn't V7 derived. So I started hunting around for C compilers.

MIT produced one at the time for the PC. It could run on the VAX and generated a.out binaries that a conversion program would convert to .COM or .EXE files. I thought this might be where the Venix compiler came with. But after playing around with it for a few hours it was clear it wasn't. First, it had a shell script cc, not a program. Second, it had a number of VAX specific instructions sprinkled inline, and that wasn't going to run on the Rainbow :).

I took a look at the portable C compiler. This I think was the real genesis of what was shipped with Venix, but old versions that support 8086 are hard to come by, even in the successor portable C compiler project that's been going for 20-odd years now. I got the cc program from that compiling with Venix. It was a bit easier to fuss around with than the V7 one (but the V7 one would be close enough to hit the bug I found out later). Looking at the old System III sources that one can find on the internet, there's a copy of the portable C compiler there, rather than the C compiler from DMR as you'll find in the 7th edition. I used the cc program from there to try to build things. I hit the jackpot: it failed faster!

So I instrumented the pcc program and discovered that the status printed after wait() in the program didn't match the status that I'd returned from the kernel. Progress!

The wait(2) system call...

I'd implemented the wait(2) system call as part of getting fork/exec working. I did it from the VENIX manual that's available online. I looked at the first part of the manual:
        int *statusp;

which shows wait taking a pointer. So I assumed this was what the kernel received in the first arg that's passed into the kernel (DX). I assumed that DS:DX pointed to an integer where I'd return the status. Most of the time, DX was something that looked like a pointer on the stack, so I just did a copyout. The problem is that's not right.

So, I took another look at the manual. At the end of the man page I saw:

8086      BX=7
              int 0xf1
              AX = pid of process
              DX = status

and then it hit me.  DX isn't a pointer to anything. After int 0xf1 AX is the pid of the process (the normal return value) and DX is the status. Disassembling wait.o confirmed this:if statusp is not 0, dx is copied back to *statusp. Doh! The classic pointer vs value mistake. Fixing my implementation to take out the copyout and replace it with setting DX in the processor context made pcc work. And cc worked. And the silly test programs I wrote in the middle to debug things worked. Woo Hoo!

Once I fixed this, all weird combinations of compilations suddenly worked for me. I could optimize, strip, etc and there were no oddities.


It helps to read the manual carefully!

I need to try to build the system. There's shell scripts to do that that don't depend on environment variables working if run natively, so I'll see if they work and see how much of the system I can generate via this route. Stay tuned.

My TODO list still contains getting env working (I don't think it is hard, but I think I need to filter things because my default env is larger than the stack on these old x86 machines). I also need to look at rebasing my emulator as a *-user qemu emulator (even if they don't take it upstream). Maybe even add PC/IX and Xenix/86 support as well so that other researchers can play around with this.

by Warner Losh ( at August 28, 2021 11:47 PM

August 27, 2021


New committer: Yasuhiro Kimura (ports)

August 27, 2021 12:00 AM

August 12, 2021

Colin Percival

EC2 boot time benchmarking

Last week I quietly released ec2-boot-bench, a tool for benchmarking EC2 instance boot times. This tool is BSD licensed, and should compile and run on any POSIX system with OpenSSL or LibreSSL installed. Usage is simple — give it AWS keys and tell it what to benchmark:
usage: ec2-boot-bench --keys <keyfile> --region <name> --ami <AMI Id>
    --itype <instance type> [--subnet <subnet Id>] [--user-data <file>]
and it outputs four values — how long the RunInstances API call took, how long it took EC2 to get the instance from "pending" state to "running" state, how long it took once the instance was "running" before port TCP/22 was "closed" (aka. sending a SYN packet got a RST back), and how long it took from when TCP/22 was "closed" to when it was "open" (aka. sending a SYN got a SYN/ACK back):
RunInstances API call took: 1.543152 s
Moving from pending to running took: 4.904754 s
Moving from running to port closed took: 17.175601 s
Moving from port closed to port open took: 5.643463 s

August 12, 2021 04:15 AM

July 31, 2021


Enhanced commit privileges: Li-Wen Hsu (doc, ports, src)

July 31, 2021 12:00 AM

July 26, 2021

Adrian Chadd

When off is not off, or "why is my amplifier pulling 30mA when it's off?"

 I have a little shed out the back with a 100W solar panel on it and a 13.8v battery. Right now it's just running a Raspberry Pi 2 powering an ADS-B decoder which works pretty well.

So then I added a little bluetooth audio amplifier from Fosi - . It's small, it's relatively efficient, and it's dumb as bricks to use.

But then I discovered something amusing.

It draws like 30mA even when turned off.

Here is the current meter when plugged into the battery side, but with it turned off.

.. and then I disconnect the power to it entirely, and  ...

High levels of what the heck.

So, I did what I always do when I find silly electronics questions - I disassembled it!

Here's the active power islands when it's turned off.

The MOSFET at the bottom is an IRF part that's .. always on. Then every other thing circled? That's also always on. That includes what look like opamp bits for the bass/treble filtering, and something op-amp-y feeding into the bluetooth audio offload PCB (that blue module.)

So what's the switch switching? Well, here's what's on the reverse of the PCB, showing the two power switch pins:

Note that one of those power pins is grounded. Yes, it's just some logic line feeding a silicon switch somewhere. And it's definitely not switching the IRF MOSFET at the beginning of the circuit - that'd be too easy.

Anyway. This amplifier will just pull ~ 350mW when turned off. I'm going to wire up a separate little switch and LED to feed power into the amplifier so I'm not discharging the battery for no reason.

But in any case, that's kinda hilarious.

by Adrian ( at July 26, 2021 10:12 PM

June 13, 2021


HardenedBSD 2021 Donation Run

Over the past couple years, we've focused on growing our infrastructure, replacing old, inherited servers with newer refurbished ones. The community's selfless help has enabled this growth.

The vast majority of our hosting is free, and we're incredibly grateful for those who provide free or low-cost hosting. We do have one leased server that costs $155/month USD. Additionally, we pay $10/month USD for the notification service.

Due to replacing the aging hardware, and replacing the occasional dead part (mostly hard drives), we're sitting at around six months worth of funding.

We need $120/month USD to keep our non-free services online. With much gratitude for existing donations and humility, we are asking the community to provide recurring monthly donations totaling a minimum of $120/month USD.

Please note that The HardenedBSD Foundation is a tax-exempt charitable organization in the USA. Donations by those in the USA are eligible for tax deduction.

We accept donations in the following ways:

  1. PayPal:
  2. GitHub sponsors:
  3. Bitcoin: 1FmbSRvZK4yC1b6ajeZWSvYXV2nmvwdWQq
  4. Ethereum: 0x9Ea8E44736AC8Ed806ef57f7F174a14D93689775
  5. Amazon Smile:

by Shawn Webb at June 13, 2021 11:59 PM

March 22, 2021


freebsd-update 13.0 caveats

By: Jason Tubnor @tubsta

We have been performing some extensive and edge case updates from FreeBSD versions earlier than 13.0. While in most cases, there have been no issues and most users will have a smooth upgrade process when we finally have 13.0-RELEASE hit but there are some issues that we hit which will need a bit of clarification and some advice on how to work them.

There has been significant changes in how ifconfig(8) interacts with VLAN(4). While most users have hosts on PVID or untagged switch ports, those that have fully tagged hosts will have issues during the upgrade with the host not being available on the network after the first reboot. VLAN interfaces will not be available until the new version of ifconfig(8) is put in place during the second ‘freebsd-update install’ run.

To get around this issue, users will either need IPMI/LOM access to their hosts to execute the second:

freebsd-update install && shutdown -r now

at which point the host will reboot and again have access to the network because of the newer ifconfig(8) being able to configure VLANs correctly. Another method is to apply the above as a cron(8) entry and have is execute a couple of minutes after the host has been rebooted. For this, you will need to know how long it takes for your host to reboot and allow a couple of extra minutes for the system to settle down post boot.

The other issue is for those that have started using the zpool checkpoint feature. If you are using legacy boot (BIOS boot), you will have issues with the system on boot after you trigger the first reboot if you have an existing 12.2 checkpoint on the system:

zio boot issue

Please note: During testing, it was found that systems that UEFI boot do not suffer this issue and users that use UEFI can use a checkpoint prior to their freebsd-update.

The following error (to assist search engines):

zio_read error: 5
zio_read error: 5
zio_read error: 5
ZFS: i/o error - all block copies unavailable
ZFS: can not read checkpoint data.

Indicates that there are some checkpoint compatibility issues in the gptzfsboot for legacy booted systems. While this could be looked into by developers, I don’t think there will be many that hit this issue and really should be just documented in the release notes. If this happens to you, simply boot the installation media, drop to the shell prompt and issue:

zpool import poolname
zpool checkpoint --discard poolname

When the system reboots, the boot loader won’t try to read-in the checkpoint status and continue booting your half upgraded system cleanly. Further testing has shown that there is no on-going issues with checkpoints once you have successfully updated your system.

by Tubsta at March 22, 2021 03:22 AM

March 15, 2021


FreeBSD 13.0 – Full Desktop Experience

By: Jason Tubnor @tubsta

With the release of FreeBSD 13.0 on the horizon, I wanted to see how it shapes up on my Lenovo T450 laptop.  Previous major releases on this laptop, using it as a workstation, felt very rough around the edges but with 13, it feels like the developers got it right.

I like to keep things simple when it comes to a desktop operating system so the description below is how I went from a fresh install of FreeBSD 13.0RC1 to a working environment that is based on using the XFCE4 desktop experience.

The FreeBSD install process is simple and well documented in other official locations, so I am not going to repeat that here.  However, some of the configuration items that I did select was to use ZFS on Root, encrypted swap and disabled all services (this is a workstation, not a server).

Once the machine had been rebooted, we need to set it up so that suspend/resume works correctly (and tests as such) and enable power management.  The main issue that people have getting the resume part of the suspend/resume to work is not having the drm or xf86 drivers loaded that are applicable to the onboard graphics.

For the T450 here, we have a standard Intel graphics chipset.  Install the following binary packages for the i915 drivers, enable them and the power management services, then reboot your machine for testing:

pkg bootstrap -f
pkg install -y drm-fbsd-kmod xf86-video-intel
kld_list=”i915kms” >> /etc/rc.conf
sysrc powerd_enable=YES
shutdown -r now

Once the machine has rebooted, you can test to see if your laptop can go into a suspend state and then resume without issue:

acpiconf -s 3

This will send the laptop into the S3 suspend state. Wait 30 seconds and then briefly press the power button. If all is working correctly, your laptop should come back to life including the screen.  This has been ‘hit and miss’ on the T450 in previous versions but seems to be working ok on 13.0.

Just a note, if you do experience some issues here, make sure your bios/firmware has been updated to the latest release.

If the above worked ok, then you can set the sysctl parameter to suspend on lid closure:

sysctl hw.acpi.lid_switch_state=S3

Also set it in the sysctl.conf file so it is set correctly each boot:

echo ‘hw.acpi.lid_switch_state=S3’ >> /etc/sysctl.conf

The final thing to do is load up xorg, XFCE4 and a few of our favourite apps to get us going.

pkg install -y xorg xfce xfce-goodies xscreensaver \
slim-freebsd-black-theme openntpd amigafonts mc \
oksh otter-browser cool-retro-term bluefish

Once all the packages have been installed, enable dbus, slim and openntpd then start the services (except slim, reboot when you are ready to start XFCE4):

sysrc dbus_enable=YES && service dbus start
sysrc openntpd_enable=YES && service openntpd start
sysrc slim_enable=YES

At some point, I’ll change to the OpenBSD ksh shell (oksh in FreeBSD packages) so I’ll add an entry into the ~/.profile file to read in ~/.kshrc

ENV=$HOME/.kshrc; export ENV

And the skeleton of my ~/.kshrc file will look something like the following:

export VISUAL=”emacs”
export EDITOR=”vi”
set -o emacs

Log out and log back in to ingest the above environment variables (or wait for the reboot below).

The final part is to get a vanilla XFCE4 desktop setup and enable/disable some of the default settings so the desktop works efficiently with the suspend/resume function and change the screensaver/lock screen.

Setup the slim display manager.  Edit the /usr/local/etc/slim.conf and change the default theme to slim-freebsd-black-theme:

current_theme slim-freebsd-black-theme

Set XFCE4 to auto-start after login, create the ~/.xinitrc file and then insert the lines:

ENV=$HOME/.kshrc; export ENV
exec startxfce4

Restart the laptop for the DM to take affect (this will also allow reboot and shutdown directly from within XFCE4 for users):

shutdown -r now

Login and once at the XFCE4 desktop, go to Applications -> Settings -> Settings Manager

In settings, scroll down to System and select ‘Session and Startup’

Select ‘Application Autostart’, de-select XFCE Screensaver, select both Screensaver and AP-SPI D-Bus Bus.

Once the above is done, log out of XFCE4 and log back in, then you can configure the xscreensaver program as well as being able to suspend and resume your laptop by closing and opening the lid at any point in the use of the laptop.

SLiM desktop manager
XFCE4 desktop with web browser
XFCE4 Desktop

by Tubsta at March 15, 2021 10:21 AM

December 16, 2020


How to configure a network dump in FreeBSD?

A network dump might be very useful for collecting kernel crash dumps from embedded machines and machines with a larger amount of RAM then available swap partition size. Besides net dumps we can also try to compress the core dump. However, often this may still not be enough swap to keep whole core dump. In such situation using network dump is a convenient and reliable way for collecting kernel dump.

December 16, 2020 11:05 PM

[PL] How play Mario?

Ugh, zaczyna się robić tłoczno, drugi post w przeciągu dwóch miesięcy, nie jest źle ;](warto dodac że post pojawia się za namową pewnej osoby (Pozdro Gyn ;>))... Dzisiaj opisze projekt nad którym ostatnio pracowałem. Pomysł użycia tej technologi chodził za mną już od igk ale dopiero ostatnio zrobiłem coś co by się nadawało do pokazania publicznie.

December 16, 2020 11:05 PM

November 06, 2020


How to run bhyve in a jail

I’ll setup a jail dedicated to run bhyve vms , for jail creation I’ll use bastillebsd

Install bastillebsd to create and manage jails.

# pkg install bastillebsd

Setup bastillebsd

Follow the getting started guide at
I’m using zfs so /usr/local/etc/bastille/bastille.conf I must edit bastille.conf (this must be done before bootstraping a release).

I used this on bastille.conf.


Create a set of rules to allow to run bhyve inside a jail edit /etc/devfs.rules, create it if does not exists.

add include $devfsrules_jail
add path vmm unhide
add path vmm/* unhide
add path tap* unhide
add path nmdm* unhide

Create a new jail that will be use these rules.

sudo bastille create --vnet test-bhyve 12.2-RELEASE em0

Modify test-bhyve jail.conf for this jail:

sudo bastille edit test-bhyve

Now add


So the jail.conf will look like:

test-bhyve {
  devfs_ruleset =25;
  enforce_statfs = 2;
  exec.consolelog = /var/log/bastille/test-bhyve_console.log;
  exec.start = '/bin/sh /etc/rc';
  exec.stop = '/bin/sh /etc/rc.shutdown';
  host.hostname = test-bhyve;
  mount.fstab = /usr/local/bastille/jails/test-bhyve/fstab;
  path = /usr/local/bastille/jails/test-bhyve/root;
  securelevel = 2;
  vnet.interface = e0b_bastille0;
  exec.prestart += "jib addm bastille0 em0";
  exec.poststop += "jib destroy bastille0";

Load the required modules:

kldload vmm
kldload nmdm

Start test-bhyve jail

sudo bastille start test-bhyve

Go inside the new jail

sudo bastille console test-bhyve

Now install vm-bhyve inside the jail follow the vm-bhyve setup at

pkg install vm-bhyve
sysrc vm_enable="YES"
mkdir /vms
sysrc vm_dir="/vms"
vm init
cp /usr/local/share/examples/vm-bhyve/* /vms/.templates/
vm switch create public
vm switch add public vtnet0
vm iso
vm create test
vm install -f test FreeBSD-12.2-RELEASE-amd64-bootonly.iso

by default a vm-bhyve vm has 256mb, if you need more you will need to run

vm config test

And configure how much RAM do you need.


If you are going to use dhcp on the vm, you will need to configure the interface to
According to this post using SYNCDHCP works, but we need to reboot the vm first.

This gives me an interface named vnet0 in my jails that i can then configure through the jail’s rc.conf. for some reason SYNCDHCP works but not DHCP in the guest rc.conf.


by cneirabustos at November 06, 2020 06:38 PM

October 03, 2020

Alexander Leidinger

Self-signed certificates and LDAPS (OpenLDAP) in PHP (or python)

This is not about how to generate a self-signed certificate, this is about how to configure an ldap client to connect securely to a ldap server which has a self-signed certificate.

Recently I was searching a lot how to make this kind of setup work, but it seems nobody is using the keywords of the headline in their HOWTOs, or everyone is not really setting up a really secure connection with self-signed certificates. As such here my try to document this for those which are interested in a secure setup.

How OpenLDAP is checking the certificates normally

OpenLDAP is using the certificate store which is configured for OpenSSL. So any certificate which is signed by one of the CAs in the OpenSSL cert-ctore are trusted.

Secure setup

Most of the time you do not expose an LDAP server to the outside where a certificate from one of the trusted-by-default CAs is needed. A certificate from your internal CA is enough, and in some cases a self-signed certificate is sufficient too.

An easy solution could be to add either the root-certificate of your CA or the self-signed certificate into the trust-store of OpenSSL (not every OS / distribution has this in the same location, you have to check where this is for your OS, for FreeBSD 13+ this is /usr/local/etc/ssl/certs/, see also certctl(8) there). But this would mean you trust the certitifacate which you put there additionally to the default certificates (modulo any blacklisting you made yourself). Theoretically this means anyone who is able to get hold of a certificate from a public-CA for your LDAP server, could perform a man-in-the-middle attack (you need to consider yourself how feasible this is in your infrastructure setup and how likely this is to happen).

More secure operation

Let’s say you run a service which needs to be able to make TLS sessions to systems which use certificates from public CAs and you want to make sure a connection to the LDAP backend can not use certificates from public CAs.

To tighten the setup in this case, you need to specify that the client which uses OpenLDAP-client libraries is using a different trust-store for the certifcate validation.

For the openldap client utilities there is a global config file for this (on FreeBSD this is /usr/local/etc/openldap/ldap.conf). For other tools, like PHP, this needs to be done in the per-user config file ~/.ldaprc. Both file have the same syntax.

With php-ldap you normally run the service either in php-fpm or in an apache-php-module. In both cases the process which runs is configured to run as a non-root user which may or may not have a home directory (in FreeBSD the www user which is typically used for that has no home directory).


  1. create a home directory
  2. create a separate trust-store for LDAP
  3. configure php-ldap / py-ldap to make use of the separate trust-store

Step 1 – create a home directory

Chose a place which is suitable, and create a directory there. It doesn’t need to be in /home, it can be anywhere. The important part is, that it is readable by the user which runs the application which is using php-ldap. It does not need to be writable by this user. In there you need to create the .ldaprc file (again, needs only be readable by the user) with the content from step 3.

Step 2 – create a separate trust-store for LDAP

In FreeBSD the global ldap config is in /usr/local/etc/openldap/ldap.conf. Theoretically you can put the trust-store for LDAP in any place wou want. In my setup I consider it to belong into /usr/local/etc/openldap/ssl/. So make a directory – like /usr/local/etc/openldap/ssl – for the trust-store, and copy the certificate of the LDAP server there.

Attention! Only the public certificate, not the private key! If you only have one file on the server for this, it is the combined key+certificate (if you don’t know or are able to deduct by looking into the file how to get rid of the key… there is a lot of info out there in the WWW which explains it). The directory and the certificate need to be accessible (read for the file, execute for the directory) by any user which shall make use of this. It does not hurt to have it accessible by everyone (you made sure there is not the private-key from the server, right?).

Step 3 – configure php-ldap / py-ldap to make use of the separate trust-store

If you use php-fpm, you need to configure a home directory in the FPM pool configureation section. As already said above, it does not need to be inside /home, but it dpends upon your needs. Here in this example let me use /home. The FPM config line to add is then something like:
env[HOME] = /home/php-fpm
You could achieve the same via changing the home directory in the password database, but this would have an effect on all processes run with this user, whereas here it is just for the php-fpm processes (and childs).

If you use apache instead of php-fpm, you need to configure something similar for the corresponding virtual host:
SetEnv HOME /home/php-fpm

With this you can now configure /home/php-fpm/.ldaprc to point to the LDAP trust-store:
TLS_CACERT /usr/local/etc/openldap/ssl/ldap_server_cert.pem
TLS_CACERTDIR /usr/local/etc/openldap/ssl

If you use some python based application, you have to do something similar… if all else fails, it needs to be via a real home directory in the password database.

If you want to use the ldap client tools with any user, you need to add those lines to the /usr/local/etc/openldap/ldap.conf file too (there you can also set the default BASE – e.g. “BASE dc=example,dc=com” – and URI – e.g. “URI ldaps://″).

After restarting php-fpm or apache, you should now be able to make really secure connections to the ldap server.

Some important things

  • Every time you change the certificate of the LDAP server, you need to update the certifacte in the clients.
  • There are two TLS modes for the LDAP server, one is “ldaps”, and one is “ldap+starttls”. If you have your LDAP server running in ldaps-mode (typically on port 639), you do not need to specify in your php-ldap using application to enable TLS (which is doing a starttls after connecting… typically on port 389), but you need to specify “ldaps://servername:639” (assuming it runs on port 639) instead of just “servername” at the place in your application where you are told to enter the server name. For py-ldap I have checked just one application (netdata), and there TLS needs to be enabled, and the server name has to be without “ldaps://” as netdata is prefixing the “ldaps://” itself if tls is enabled.
  • Some places in the internet are telling to add “TLS_REQCERT never” into ldap.conf / .ldaprc. Technically this is not needed. Depending on your point of view this can either be good or bad (specifying it saves some CPU cycles on the server and the client, and some transfer time over the network – not specifying it allows to validate the certificated received to be compared to the certifcate being available locally, but I do not know if OpenLDAP is doing this, nor did I spend some time to evaluate if this improves security (if the important parts of the certificate are out-of-sync, the connection will fail)).
Send to Kindle


by netchild at October 03, 2020 11:08 AM

July 30, 2020


Audio subsystem hardware internals

I wrote an introductory article on how the audio subsystem on SBCs work: CODECs, I2S, DTS, whole nine yards. WordPress editor didn’t seem to be a very convenient tool for this kind of write up so I gave asciidoc a try and so far liked it.

Link to the article:

by gonzo at July 30, 2020 07:13 AM

June 04, 2020


yubikey-agent on FreeBSD

Some time ago Filippo Valsorda wrote yubikey-agent, seamless SSH agent for YubiKeys. I really like YubiKeys and worked on the FreeBSD support for U2F in Chromium and pyu2f, getting yubikey-agent ported looked like an interesting project. It took some hacking to make it work but overall it wasn’t hard. Following is the roadmap on how to get it set up on FreeBSD. The actual details depend on your system (as you will see)

The first step is to set up middleware for accessing smart cards (YubiKey implements CCID smart-card protocol). The pcsc-lite package provides a daemon and a library for clients to communicate with the daemon. ccid is a plugin for pcsc-lite that implements the actual CCID protocol over USB. devd rules are to make the daemon re-scan USB devices on hotplug

sudo pkg install ccid pcsc-lite
sudo mkdir -p /usr/local/etc/devd
sudo tee /usr/local/etc/devd/pcscd.conf << __EOF__
attach 100 {
        device-name "ugen[0-9]+";
        action "/usr/local/sbin/pcscd -H";
detach 100 {
        device-name "ugen[0-9]+";
        action "/usr/local/sbin/pcscd -H";

sudo service devd restart
sudo sysrc pcscd_enable="YES
sudo service pcscd start

go and git are build requirements for the app. go get command is required because FreeBSD support was only recently merged into piv-go and the latest release, referenced in go.mod, still does not have it. go install command installs the app in ~/go/bin/. When new version of piv-go is released and yubikey-agent switches to using it, all these commands can be replaced with single go get command.

sudo pkg install go git
git clone
cd yubikey-agent
go get
go build
go install

The binary is in ~/go/bin/ directory, you can add it to your $PATH to type less.

The next step is setting up a Yubikey, it’s well documented on the official site. One caveat though is if PIN length is less than 6 chars the setup fails with the somewhat confusing message: “‼ The default PIN did not work.”

The actual usage of yubikey-agent depends on your setup. First of all, yubikey-agent is a “eventually GUI” app. At some point, when entering PIN is required it starts pinentry command which task is to present user with a dialog entry, get PIN, and pass it to the app. There are multiple pinentry flavors, with different front-ends: TTY, Qt, GTK. gopass module used in yubikey-agent does not work with plain TTY backend, and requires pinentry to be a GUI app. On Debian/Ubuntu users can switch between flavors and make /usr/bin/pinentry point to either Qt5 or GTK version, but in FreeBSD /usr/local/bin/pinentry is always TTY one. I worked around it by installing pinentry-qt5 package and making symlink.

sudo pkg install pinentry-qt5
sudo ln -s /usr/local/bin/pinentry-qt5 /usr/local/bin/pinentry

If you need /usr/local/bin/pinentry to be TTY version for some other stuff, there may be a problem. How to work around this depends on your requirements. I don’t have a ready recipe.

Because yubikey-agent is “eventually GUI” you can either start it in .xsession or .xinitrc files or start it some other way with DISPLAY env variable set. Other than that official documentation is a good source of information on how to use it.

by gonzo at June 04, 2020 07:03 AM

March 19, 2020

Alexander Leidinger

Fighting the Coronavirus with FreeBSD (Folding@Home)

Photo by Fusion Medical Animation on Unsplash

Here is a quick HOWTO for those which want to provide some FreeBSD based compute resources to help finding vaccines. I have not made a port out of this and do not know yet if I get the time to make one. If someone wants to make a port, go ahead, do not wait for me.

UPDATE 2020-03-22: 0mp@ made a port out of this, it is in “biology/linux-foldingathome”.

  • Download the linux RPM of the Folding@Home client (this covers fahclient only).
  • Enable the linuxulator (kernel moduls and linux_base (first part of chapter 10.2) is enough).
  • Make sure linprocfs/linsysfs are mounted in /compat/linux/{proc|sys}.
  • cd /compat/linux
  • tar -xf /path/to/fahclient....rpm
  • add the “fahclient” user (give it a real home directory)
  • make sure there is no /compat/linux/dev or alternatively mount devfs there
  • mkdir /compat/linux/etc/fahclient
  • cp /compat/linux/usr/share/doc/fahclient/sample-config.xml /compat/linux/etc/fahclient/config.xml
  • chown -R fahclient /compat/linux/etc/fahclient
  • edit /compat/linux/fahclient/config.xml: modify user (mandatory) / team (optional: FreeBSD team is 11743) / passkey (optional) as appropriate (if you want to control the client remotely, you need to modify some more parts, but somehow the client “loses” a filedescriptor and stops working as it should if you do that on FreeBSD)
  • If you have the home directories of the users as no-exec (e.g. seperate ZFS datasets with exec=off): make sure the home directory of the fahclient user has exec permissions enabled
  • cd ~fahclient (important! it tries to write to the current work directory when you start it)
  • Start it: /usr/sbin/daemon /compat/linux/usr/bin/FAHClient /compat/linux/etc/fahclient/config.xml --run-as fahclient --pid-file=/var/run/ >/dev/null 2>&1

Per default it will now pick up some SARS-CoV‑2 (COVID-19) related folding tasks. There are some more config options (e.g. how much of the system resources are used). Please refer to the official Folding@Home site for more information about that. Be also aware that there is a big rise in compute resources donated to Folding@Home, so the pool of available work units may be empty from time to time, but they are working on adding more work units. Be patient.

Send to Kindle


by netchild at March 19, 2020 08:47 AM

October 22, 2018

Dag-Erling Smørgrav

DNS over TLS in FreeBSD 12

With the arrival of OpenSSL 1.1.1, an upgraded Unbound, and some changes to the setup and init scripts, FreeBSD 12.0, currently in beta, now supports DNS over TLS out of the box.

DNS over TLS is just what it sounds like: DNS over TCP, but wrapped in a TLS session. It encrypts your requests and the server’s replies, and optionally allows you to verify the identity of the server. The advantages are protection against eavesdropping and manipulation of your DNS traffic; the drawbacks are a slight performance degradation and potential firewall traversal issues, as it runs over a non-standard port (TCP port 853) which may be blocked on some networks. Let’s take a look at how to set it up.

Basic setup

As a simple test case, let’s set up our 12.0-ALPHA10 VM to use Cloudflare’s DNS service:

# uname -r
# cat >/etc/rc.conf.d/local_unbound <<EOF
# service local_unbound start
Performing initial setup.
/var/unbound/forward.conf created
/var/unbound/lan-zones.conf created
/var/unbound/control.conf created
/var/unbound/unbound.conf created
/etc/resolvconf.conf not modified
Original /etc/resolv.conf saved as /var/backups/resolv.conf.20181021.192629
Starting local_unbound.
Waiting for nameserver to start... good
# host is an alias for has address has IPv6 address 2610:1c1:1:606c::50:15 mail is handled by 0 .

Note that this is not a configuration you want to run in production—we will come back to this later.


The downside of DNS over TLS is the performance hit of the TCP and TLS session setup and teardown. We demonstrate this by flushing our cache and (rather crudely) measuring a cache miss and a cache hit:

# local-unbound-control reload
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.553 total
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.005 total

Compare this to querying our router, a puny Soekris net5501 running Unbound 1.8.1 on FreeBSD 11.1-RELEASE:

# time host gw >x
host gw > x 0.00s user 0.00s system 0% cpu 0.232 total
# time host >x
host gw > x 0.00s user 0.00s system 0% cpu 0.008 total

or to querying Cloudflare directly over UDP:

# time host >x      
host > x 0.00s user 0.00s system 0% cpu 0.272 total
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.013 total

(Cloudflare uses anycast routing, so it is not so unreasonable to see a cache miss during off-peak hours.)

This clearly shows the advantage of running a local caching resolver—it absorbs the cost of DNSSEC and TLS. And speaking of DNSSEC, we can separate that cost from that of TLS by reconfiguring our server without the latter:

# cat >/etc/rc.conf.d/local_unbound <<EOF
# service local_unbound setup
Performing initial setup.
Original /var/unbound/forward.conf saved as /var/backups/forward.conf.20181021.205328
/var/unbound/lan-zones.conf not modified
/var/unbound/control.conf not modified
Original /var/unbound/unbound.conf saved as /var/backups/unbound.conf.20181021.205328
/etc/resolvconf.conf not modified
/etc/resolv.conf not modified
# service local_unbound start
Starting local_unbound.
Waiting for nameserver to start... good
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.080 total
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.004 total

So does TLS add nearly half a second to every cache miss? Not quite, fortunately—in our previous tests, our first query was not only a cache miss but also the first query after a restart or a cache flush, resulting in a complete load and validation of the entire path from the name we queried to the root. The difference between a first and second cache miss is quite noticeable:

# time host >x 
host > x 0.00s user 0.00s system 0% cpu 0.546 total
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.004 total
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.168 total
# time host >x
host > x 0.00s user 0.00s system 0% cpu 0.004 total

Revisiting our configuration

Remember when I said that you shouldn’t run the sample configuration in production, and that I’d get back to it later? This is later.

The problem with our first configuration is that while it encrypts our DNS traffic, it does not verify the identity of the server. Our ISP could be routing all traffic to to its own servers, logging it, and selling the information to the highest bidder. We need to tell Unbound to validate the server certificate, but there’s a catch: Unbound only knows the IP addresses of its forwarders, not their names. We have to provide it with names that will match the x509 certificates used by the servers we want to use. Let’s double-check the certificate:

# :| openssl s_client -connect |& openssl x509 -noout -text |& grep DNS
DNS:*, IP Address:, IP Address:,, IP Address:2606:4700:4700:0:0:0:0:1111, IP Address:2606:4700:4700:0:0:0:0:1001

This matches Cloudflare’s documentation, so let’s update our configuration:

# cat >/etc/rc.conf.d/local_unbound <<EOF
# service local_unbound setup
Performing initial setup.
Original /var/unbound/forward.conf saved as /var/backups/forward.conf.20181021.212519
/var/unbound/lan-zones.conf not modified
/var/unbound/control.conf not modified
/var/unbound/unbound.conf not modified
/etc/resolvconf.conf not modified
/etc/resolv.conf not modified
# service local_unbound restart
Stopping local_unbound.
Starting local_unbound.
Waiting for nameserver to start... good
# host is an alias for has address has IPv6 address 2610:1c1:1:606c::50:15 mail is handled by 0 .

How can we confirm that Unbound actually validates the certificate? Well, we can run Unbound in debug mode (/usr/sbin/local-unbound -dd -vvv) and read the debugging output… or we can confirm that it fails when given a name that does not match the certificate:

# perl -p -i -e 's/cloudflare/cloudfire/g' /etc/rc.conf.d/local_unbound
# service local_unbound setup
Performing initial setup.
Original /var/unbound/forward.conf saved as /var/backups/forward.conf.20181021.215808
/var/unbound/lan-zones.conf not modified
/var/unbound/control.conf not modified
/var/unbound/unbound.conf not modified
/etc/resolvconf.conf not modified
/etc/resolv.conf not modified
# service local_unbound restart
Stopping local_unbound.
Waiting for PIDS: 33977.
Starting local_unbound.
Waiting for nameserver to start... good
# host
Host not found: 2(SERVFAIL)

But is this really a failure to validate the certificate? Actually, no. When provided with a server name, Unbound will pass it to the server during the TLS handshake, and the server will reject the handshake if that name does not match any of its certificates. To truly verify that Unbound validates the server certificate, we have to confirm that it fails when it cannot do so. For instance, we can remove the root certificate used to sign the DNS server’s certificate from the test system’s trust store. Note that we cannot simply remove the trust store entirely, as Unbound will refuse to start if the trust store is missing or empty.

While we’re talking about trust stores, I should point out that you currently must have ca_root_nss installed for DNS over TLS to work. However, 12.0-RELEASE will ship with a pre-installed copy.


We’ve seen how to set up Unbound—specifically, the local_unbound service in FreeBSD 12.0—to use DNS over TLS instead of plain UDP or TCP, using Cloudflare’s public DNS service as an example. We’ve looked at the performance impact, and at how to ensure (and verify) that Unbound validates the server certificate to prevent man-in-the-middle attacks.

The question that remains is whether it is all worth it. There is undeniably a performance hit, though this may improve with TLS 1.3. More importantly, there are currently very few DNS-over-TLS providers—only one, really, since Quad9 filter their responses—and you have to weigh the advantage of encrypting your DNS traffic against the disadvantage of sending it all to a single organization. I can’t answer that question for you, but I can tell you that the parameters are evolving quickly, and if your answer is negative today, it may not remain so for long. More providers will appear. Performance will improve with TLS 1.3 and QUIC. Within a year or two, running DNS over TLS may very well become the rule rather than the experimental exception.

by Dag-Erling Smørgrav at October 22, 2018 09:36 AM

April 09, 2018

Dag-Erling Smørgrav

Twenty years

Yesterday was the twentieth anniversary of my FreeBSD commit bit, and tomorrow will be the twentieth anniversary of my first commit. I figured I’d split the difference and write a few words about it today.

My level of engagement with the FreeBSD project has varied greatly over the twenty years I’ve been a committer. There have been times when I worked on it full-time, and times when I did not touch it for months. The last few years, health issues and life events have consumed my time and sapped my energy, and my contributions have come in bursts. Commit statistics do not tell the whole story, though: even when not working on FreeBSD directly, I have worked on side projects which, like OpenPAM, may one day find their way into FreeBSD.

My contributions have not been limited to code. I was the project’s first Bugmeister; I’ve served on the Security Team for a long time, and have been both Security Officer and Deputy Security Officer; I managed the last four Core Team elections and am doing so again this year.

In return, the project has taught me much about programming and software engineering. It taught me code hygiene and the importance of clarity over cleverness; it taught me the ins and outs of revision control; it taught me the importance of good documentation, and how to write it; and it taught me good release engineering practices.

Last but not least, it has provided me with the opportunity to work with some of the best people in the field. I have the privilege today to count several of them among my friends.

For better or worse, the FreeBSD project has shaped my career and my life. It set me on the path to information security in general and IAA in particular, and opened many a door for me. I would not be where I am now without it.

I won’t pretend to be able to tell the future. I don’t know how long I will remain active in the FreeBSD project and community. It could be another twenty years; or it could be ten, or five, or less. All I know is that FreeBSD and I still have things to teach each other, and I don’t intend to call it quits any time soon.


by Dag-Erling Smørgrav at April 09, 2018 08:35 PM

February 05, 2018

Remko Lodder

Reponse zones in BIND (RPZ/Blocking unwanted traffic).

A while ago, my dear colleague Mattijs came with an interesting option in BIND. Response zones. One can create custom "zones" and enforce a policy on that.

I never worked with it before, so I had no clue at all what to expect from it. Mattijs told me how to configure it (see below for an example) and offered to slave his RPZ policy-domains.

All of a sudden I was no longer getting a lot of ADS/SPAM and other things. It was filtered. Wow!

His RPZ zones were custom made and based on PiHole, where PiHole adds hosts to the local "hosts" file and sends it to (your local machine), which prevents it to reach the actual server at all, RPZ policies are much stronger and more dynamic.

RPZ policies offer the use of "redirecting" queries. What do I mean with that? well you can force a ADVERTISEMENT (AD for short) site / domain to the RPZ policy and return a NXDOMAIN. It no longer exists for the end-user. But you can also CNAME it to a domain/host you own and then add a webserver to that host and tell the user query'ing the page: "The site you are trying to reach had been pro-actively blocked by the DNS software. This is an automated action and an automated response. If you feel that this is not appropriate, please let us know on <mail link>", or something like that.

Once I noticed that and saw the value, I immediately saw the benefit for companies and most likely schools and home people. Mattijs had a busy time at work and I was recovering from health issues, so I had "plenty" of time to investigate and read on this. The RPZ policies where not updated a lot and caused some problems for my ereaders for example ( was used by them, see another post on this website for being grumpy about that). And I wanted to learn more about it. So what did I do?

Yes, I wrote my own parser. In perl. I wrote a "rpz-generator" (its actually called like that). I added the sources Mattijs used and generated my own files. They are rather huge, since I blocked ads, malware, fraud, exploits, windows stuff and various other things (gambling, fakenews, and stuff like that).

I also included some whitelists, because msfctinc was added to the lists and it made my ereaders go beserk, and we play a few games here and there which uses some advertisement sites, so we wanted to exempt them as well. It's better to know which ones they are and selectively allow them, then having traffic to every data collector out there.

This works rather well. I do not get a lot of complaints that things are not working. I do see a lot of queries going to "banned" sites everyday. So it is doing something .The most obvious one is that search results on google, not always are clickable. The ones that have those [ADV] sites, are blocked because they are advertising google sponsored sites, and they are on the list.. and google-analytics etc. It doesn't cause much harm to our internet surfing or use experience, with the exception of the ADV sites I just mentioned. My wife sometimes wants to click on those because she searches for something that happends to be on that list, but apart from that we are doing just fine.

One thing though, I wrote my setup and this article with my setup using "NXDOMAIN" which just gives back "site does not exist" messages. I want to make my script more smart by making it a selectable, so that some categories are CNAMED to a filtering domain and webpage, and some are NXDOMAIN'ed. If someone has experience with that, please show me some idea's and how that looks like and whether your end-users can do something with it or not. I think schools will be happy to present a block-page instead of NXdomain'ing some sites 🙂

Acknowledgements: Mattijs for teaching and showing me RPZ, ISC for placing RPZ in NAMED, and for having such excellent documentation to RPZ. The perl developers for having such a great tool around, and the various sites I use to get the blocklists from. Thank you all!

If you want to know more about the tool, please contact me and we can share whatever information is available 🙂

by Remko Lodder at February 05, 2018 11:09 PM

August 29, 2017

Remko Lodder

FreeBSD: Using Open-Xchange on FreeBSD

If you go looking for a usable webmail application, then you might end up with Open-Xchange (OX for short). Some larger ISP's are using OX as their webmail application for customers. It has a multitude of options available, using multiple email accounts, caldav/carddav included (not externally (yet?)) etc. There are commercial options available for these ISP's, but also for smaller resellers etc.

But, there is also the community edition available. Which is the installation you can run for free on your machine(s). It does not have some of the fancy modules that large setups need and require, and some updates might follow a bit later which are more directly delivered to paying customers, but it is very complete and usable.

I decided to setup this for my private clients who like to use a webmail client to access their email. At first I ran this on a VM using Bhyve on FreeBSD. The VM ran on CentOS6 and had the necessary bits installed for the OX setup (see: I modified the files I needed to change to get this going, and there, it just worked. But, running on a VM, with ofcourse limited CPU and Memory power assigned (There is always a cap) and it being emulated, I was not very happy with it. I needed to maintain an additional installation and update it, while I have this perfectly fine FreeBSD server instead. (Note that I am not against using bhyve at all, it works very well, but I wanted to reduce my maintenance base a bit :-)).

So a few days ago I considered just moving the stuff over to the FreeBSD host instead. And actually it was rather trivial to do with the working setup on CentOS.

At this moment I do not see an easy way to get the source/components directly from within FreeBSD. I have asked OX for help on this, so that we can perhaps get this sorted out and perhaps even make a Port/pkg out of this for use with FreeBSD.

The required host changes and software installation

The first thing that I did was to create a zfs dataset for /opt. The software is normally installed there, and in this case I wanted to have a contained location which I can snapshot, delete, etc, without affecting much of the normal system. I copied over the /opt/open-xchange directory from my CentOS installation. I looked at the installation on CentOS and noticed that it used a specific user 'open-xchange', which I created on my FreeBSD host. I changed the files to be owned by this user. Getting a process listing on the CentOS machine also revealed that it needed Java/JDK. So I installed the openjdk8 pkg (''pkg install openjdk8''). The setup did not yet start, there were errors about /bin/bash missing. Obviously that required installing bash (''pkg install bash'') and you can go with two ways, you can alter every shebang (#!) to match /usr/local/bin/bash (or better yet #!/usr/bin/env bash), or you can symlink /usr/local/bin/bash to /bin/bash, which is what I did (I asked OX to make it more portable by using the env variant instead).

The /var/log/open-xchange directory does not normally exist, so I created that and made sure that ''open-xchange'' could write to that. (mkdir /var/log/open-xchange && chown open-xchange /var/log/open-xchange).

I was able to startup the /opt/open-xchange/sbin/open-xchange process with that. I could not yet easily reach it, on the CentOS installation there are two files in the Apache configuration that needed some attention on my FreeBSD host. The Apache include files: ox.conf and proxy_http.conf will give away hints about what to change. In my case I needed to do the redirect on the Vhost that runs OX (RedirectMatch ^/$ /appsuite/) and make sure the /var/www/html/appsuite directory is copied over from the CentOS installation as well. You can stick it in any location, as long as you can reach it with your webuser and Alias it to the proper directory and setup directory access).

Apache configuration (Reverse proxy mode)

The proxy_http.conf file is more interesting, it includes the reverse proxy settings to be able to connect to the java instance of OX and service your clients. I needed to add a few modules in Apache so that it could work, I already had several proxy modules enabled for different reasons, so the list below can probably be trimmed a bit to the exact modules needed, but since this works for me, I might as well just show you;

LoadModule slotmem_shm_module libexec/apache24/
LoadModule deflate_module libexec/apache24/
LoadModule expires_module libexec/apache24/
LoadModule proxy_module libexec/apache24/
LoadModule proxy_connect_module libexec/apache24/
LoadModule proxy_http_module libexec/apache24/
LoadModule proxy_scgi_module libexec/apache24/
LoadModule proxy_wstunnel_module libexec/apache24/
LoadModule proxy_ajp_module libexec/apache24/
LoadModule proxy_balancer_module libexec/apache24/
LoadModule lbmethod_byrequests_module libexec/apache24/
LoadModule lbmethod_bytraffic_module libexec/apache24/
LoadModule lbmethod_bybusyness_module libexec/apache24/

After that it was running fine for me. My users can login to the application and the local directory's are being used instead of the VM which ran it first. If you notice previous documentation on this subject, you will notice that there are more third party packages needed at that time. It could easily be that there are more modules needed than that I wrote about. My setup was not clean, the host already runs several websites (one of them being this one) and ofcourse support packages were already installed.

Updating is currently NOT possible. The CentOS installation requires running ''yum update'' periodically, but that is obviously not possible on FreeBSD. The packages used within CentOS are not directly usable for FreeBSD. I have asked OX to provide the various Community base and optional modules as .tar.gz files (raw) so that we can fetch them and install them on the proper location(s). As long as the .js/.jar files etc are all there and the scripts are modified to start, it will just work. I have not (yet) created a startup script for this yet. For the moment I will just start the VM and see whether there are updates and copy them over instead. Since I did not need to do additional changing on the main host, it is a very easy and straight forward process in this case.


There is no support for OX on FreeBSD. Ofcourse I would like to see at least some support to promote my favorite OS more, but that is a financial situation. It might not cost a lot to deliver the .tar.gz files so that we can package them and spread the usage of OX on more installations (and thus perhaps add revenue for OX as commercial installation), but it will cost FTE's to support more then that. If you see a commercial opportunity, please let them know so that this might be more and more realistic.

The documentation written above is just how I have setup the installation and I wanted to share it with you. I do not offer support on it, but ofcourse I am willing to answer questions you might have about the setup etc. I did not include the vhost configuration in it's entirely, if that is a popular request, I will add it to this post.

Open Questions to OX:

So as mentioned I have questioned OX for some choices:

  • Please use a more portable path for the Bash shell (#!/usr/bin/env bash)
  • Please allow the use of a different localbase (/usr/local/open-xchange for example)
  • Please allow FreeBSD packagers to fetch a "clean" .tar.gz, so that we can package this for OX and distribute it for our end-users.
  • Unrelated to the post above: Please allow the usage of external caldav/carddav providers


I have found another thing that I needed to change. I needed to use gsed (Gnu-sed) instead of FreeBSD-sed so that the listuser scripts work. Linux does that a bit differently but if you replace sed with gsed those scripts will work fine.

I have not yet got some feedback from OX.

by Remko Lodder at August 29, 2017 07:48 AM

April 11, 2017

Eric Anholt

This week in vc4 (2017-04-10): dmabuf fencing, meson

The big project for the last two weeks has been developing dmabuf fencing support for vc4.  Without dmabuf fences, when passing buffers between devices the user needs to manually wait for the job to finish on one (say, camera snapshot) before letting the other device get started (accumulating GL commands to texture from the camera snapshot).  That means leaving both devices idle for a moment while the CPU accumulates the command stream for the consumer, but the bigger pain is that it requires that the end user manage the synchronization.

With dma-buf fencing in the kernel, a "reservation object" generated by the dma-buf exporter tracks the fences of the various devices using the shared object, and then the device trivers get to look at that list and wait on on each others' fences when using it.

So far, I've got my reservations and fences being exported from vc4, so that pl111 display can wait for vc4 to be done before actually putting a new pageflip up on the screen.  I haven't quite hooked up the other direction, for camera capture into vc4 display or GL texturing (I don't have a testcase for this, as the current camera driver doesn't expose dmabufs), but it shouldn't be hard.

On the meson front, rendercheck is now converted to meson upstream.  I've made more progress on the X Server:  Xorg is now building, and even successfully executes Xorg -pogo with the previous modesetting driver in place.  The new modesetting driver is failing mysteriously.  With a build hack I got from the meson folks and some work from ajax, the sdksyms script I complained about in my last post isn't used at all on the meson build.  And, best of all, the meson devs have written the code needed for us to not even need the build hack I'm using.

It's so nice to be using a build system that's an actual living software project.

by anholt at April 11, 2017 12:48 AM

March 27, 2017

Eric Anholt

This week in vc4 (2017-03-27): Upstream PRs, more CMA, meson

Last week I sent pull requests for bcm2835 changes for 4.12.  We've got some DT updates for HDMI audio, DSI, and SDHOST, and defconfig changes to enable SDHOST.  The DT changes to actually enable SDHOST (and get wifi working on Pi3) won't land until 4.13.

I also wrote a patch to enable using more than 256MB of CMA memory (and not require any particular alignment).  The 256MB limit was due to a hardware bug: the binner's memory allocations get dereferenced with their top 4 bits set to the top 4 bits of the tile state data array's address.  Given that tile state allocations happen after CL setup (while the binner is running and throwing overflow interrupts), there was no way to guarantee that we could find overflow memory with the top bits matching.

The new solution, suggested by someone from the set top box group, is to allocate a single 16MB to 32MB buffer at HW init time, and return all of those types of allocations out of it, since it turns out you don't need much to complete rendering of any given scene.  I've been mulling over the details of a solution for a while, and finally wrote and tested the patch I wanted (tricky parts included freeing the memory when the hardware was idle, and how to track the lifetimes of the sub-allocations).  Results look good, and I'll be submitting it this week.

However, I spent most of the week on converting the X Server over to meson

Meson is a delightful new build system (based around Ninja on Linux) that massively speeds up builds, while also being portable to Windows (unlike autotools generally).  If you've ever tried to build the X stack on Raspberry Pi, you know that autotools is painfully slow.  It's also been the limiting factor for me in debugging my scripts for CI for the X Server -- something we'd really like to be doing as we hack on glamor or do refactors in the core.

So far all I've landed in this project is code deletion, as I find build options that aren't hooked up to anything, or code that isn't hooked up to build options.  This itself will speed up our builds, and ajax has been working in parallel on deleting a bunch of code that makes the build messier than it needs to be.  I've also submitted patches for rendercheck converting to meson (as a demo of what the conversion looks like), and I have Xephyr, Xvfb, Xdmx, and Xwayland building in the X Server with meson.

So far the only stumbling block for the meson conversion of the X Server is the sdksyms.c file.  It's the ugliest part of the build -- running the C preprocessor on a generated .c that #includes a bunch of .h tiles, then running the output of that through awk and trying to parse C using regular expressions.  This is, as you might guess, somewhat fragile.

My hope for a solution to this is to just quit generating sdksyms.c entirely.  Using ELF sections, we can convince the linker to not garbage collect symbols that it thinks are unused.  Then we get to just decorate symbols with XORG_EXPORT or XORG_EXPORT_VAR (unfortunately have to have separate sections for RO vs RW contents), and Xorg will have the correct set of symbols exported.  I started on a branch for this, ajax got it actually building, and now we just need to bash the prototypes so that the same set of symbols are exported before/after the conversion.

by anholt at March 27, 2017 10:43 PM

October 25, 2016

Murray Stokely

FreeBSD on Intel NUCs

I've been away from FreeBSD for a few years but I wanted some more functionality on my home network that I was able to configure with my Synology NAS and router. Specifically, I wanted:

  • a configurable caching name server that would serve up authoritative private names on my LAN and also validates responses with DNSSEC.
  • a more configurable DHCP server so I could make the server assign specific IPs to specific MAC addresses.
  • more compute power for transcoding videos for Plex.

Running FreeBSD 11 on an Intel NUC seemed like an ideal solution to keep my closet tidy. As of this week, $406.63 on Amazon buys a last generation i3 Intel NUC mini PC (NUC5I3RYH), with 8GB of RAM and 128GB of SSD storage. This was the first model I tried since I found reports of others using this with FreeBSD online, but I was also able to get it working on the newer generation i5 based NUC6i5SYK with 16GB of RAM and 256GB of SSD. The major issue with these NUCs is that the Intel wireless driver is not supported in FreeBSD. I am not doing anything graphical with these boxes so I don't know how well the graphics work, but they are great little network compute nodes.


I downloaded the FreeBSD 11 memory stick images, and was pleased to see that the device booted fine off the memory stick without any BIOS configuration required. However, my installation failed trying to mount root ("Mounting from ufs:/dev/ufs/FreeBSD_Install failed with error 19."). Installation from an external USB DVD drive and over the network with PXE both proved more successful at getting me into bsdinstaller to complete the installation.

I partitioned the 128GB SSD device with 8GB of swap and the rest for the root partition (UFS, Journaled and Soft Updates). After installation I edited /etc/fstab to add a tmpfs(5) mount for /tmp. The dmesg output for this host is available in a Gist on Github.

Warren Block's article on SSD on FreeBSD and the various chapters of the FreeBSD Handbook were helpful. There were a couple of tools that were also useful in probing the performance of the SSD with my FreeBSD workload:

  • The smartctl tool in the sysutils/smartmontools package allows one to read detailed diagnostic information from the SSD, including wear patterns.
  • The basic benchmark built into diskinfo -t reports that the SSD is transferring 503-510MB/second.
But how well does it perform in practice?

Rough Benchmarks

This post isn't meant to report a comprehensive suite of FreeBSD benchmarks, but I did run some basic tests to understand how suitable these low power NUCs perform in practice. To start with, I downloaded the 11-stable source from Subversion and measured the build times to understand performance of the new system. All builds were done with a minimal 2 line make.conf:


Build Speed

Build CommandEnvironmentReal Times
make -j4 buildkernel/usr/src and /usr/obj on SSD10.06 minutes
make -j4 buildkernel/usr/src on SSD, /usr/obj on tmpfs9.65 minutes
make -j4 buildworld/usr/src and /usr/obj on SSD1.27 hours
make buildworld/usr/src and /urs/obj on SSD3.76 hours


In addition to the build times, I also wanted to look more directly at the performance reading from flash and reading from the NFS mounted home directories on my 4-drive NAS. I first tried Bonnie++, but then ran into a 13-year old bug in the NFS client of FreeBSD. After switching to Bonnie, I was able to gather some reasonable numbers. I had to use really large file sizes for the random write test to eliminate most of the caching that was artificially inflating the results. For those that haven't seen it, Brendan Gregg's excellent blog post highlights some of the issues of file system benchmarks like Bonnie.

Average of 3 bonnie runs with 40GB block size
ConfigurationRandom I/OBlock InputBlock Output
Seeks/SecCPU UtilizationReads/secCPU UtilizationWrites/secCPU Utilization

The block input rates from my bonnie benchmarks on the SSD were within 5% of the value provided by the much quick and dirtier diskinfo -t test.

Running Bonnie with less than 40GB file size yielded unreliable benchmarks due to caching at the VM layer. The following boxplot shows the random seek performance during 3 runs each at 24, 32, and 40GB file sizes. Performance starts to even off at this level but with smaller file sizes the reported random seek performance is much higher.

Open Issues

As mentioned earlier, I liked the performance I got with running FreeBSD on a 2015-era i3 NUC5I3RYH so much that I bought a newer, more powerful second device for my network. The 2016-era i5 NUC 6i5SYK is also running great. There are just a few minor issues I've encountered so far:

  • There is no FreeBSD driver for the Intel Wireless chip included with this NUC. Code for other platforms exists but has not been ported to FreeBSD.
  • The memory stick booting issue described in the installation section. It is not clear if it didn't like my USB stick for some reason, or the port I was plugging into, or if additional boot parameters would have solved the issue. Documentation and/or code needs to be updated to make this clearer.
  • Similarly, the PXE Install instructions were a bit scattered. The PXE section of the Handbook isn't specifically targetting new manual installations into bsdinstall. There are a few extra things you can run into that aren't documented well or could be streamlined.
  • Graphics / X11 are outside of the scope of my needs. The NUCs have VESA mounts so you can easily tuck them behind an LCD monitor, but it is not clear to me how well they perform in that role.

by Murray ( at October 25, 2016 03:27 AM

April 07, 2016

FreeBSD Foundation

Introducing a New Website and Logo for the Foundation

The FreeBSD Foundation is pleased to announce the debut of our new logo and website, signaling the ongoing evolution of the Foundation identity, and ability to better serve the FreeBSD Project. Our new logo was designed to not only reflect the established and professional nature of our organization, but also to represent the link between the Project and the Foundation, and our commitment to community, collaboration, and the advancement of FreeBSD.

We did not make this decision lightly.  We are proud of the Beastie in the Business Suit and the history he encompasses. That is why you’ll still see him make an appearance on occasion. However, as the Foundation’s reach and objectives continue to expand, we must ensure our identity reflects who we are today, and where we are going in the future. From spotlighting companies who support and use FreeBSD, to making it easier to learn how to get involved, spread the word about, and work within the Project, the new site has been designed to better showcase, not only how we support the Project, but also the impact FreeBSD has on the world. The launch today marks the end of Phase I of our Website Development Project. Please stay tuned as we continue to add enhancements to the site.

We are also in the process of updating all our collateral, marketing literature, stationery, etc with the new logo. If you have used the FreeBSD Foundation logo in any of your marketing materials, please assist us in updating them. New Logo Guidelines will be available soon. In the meantime, if you are in the process of producing some new literature, and you would like to use the new Foundation logo, please contact our marketing department to get the new artwork.

Please note: we've moved the blog to the new site. See it here.

by Anne Dickison ( at April 07, 2016 04:40 PM

February 26, 2016

FreeBSD Foundation

FreeBSD and ZFS

ZFS has been making headlines lately, so it seems like the right time to talk about the longstanding relationship between FreeBSD and ZFS.

For nearly seven years, FreeBSD has included a production quality ZFS implementation, making it one of the key features of the FreeBSD operating system. ZFS is a combined file system and volume manager. Decoupling physical media from logical volumes allows free space to be efficiently shared between all of the file systems. ZFS introduced unprecedented data integrity and reliability guarantees to storage on FreeBSD. ZFS supports varying levels of redundancy for tolerance of hardware failures and includes cryptographic checksums on all data to guard against corruption.

Allan Jude, VP of Operations at ScaleEngine and coauthor of FreeBSD Mastery: ZFS, said “We started using ZFS in 2011 because we needed to safely store a huge quantity of video for our customers. FreeBSD was, and still is, the best platform for deploying ZFS in production. We now store more than a petabyte of video using ZFS, and use ZFS Boot Environments on all of our servers.”

So why does FreeBSD include ZFS and contribute to its continued development? FreeBSD community members understand the need for continued development work as technologies evolve. OpenZFS is the truly open source successor to the ZFS project and the FreeBSD Project has participated in OpenZFS since its founding in 2013. FreeBSD developers and those from Delphix, Nexenta, Joyent, the ZFS on Linux project, and the Illumos project work together to continue improving OpenZFS.

FreeBSD’s unique open source infrastructure, copyfree license, and engaged community support the integration of a variety of free software components, including OpenZFS. FreeBSD makes an excellent operating system for servers and end users, and it provides a foundation for many open source projects and commercial products.

We're happy that ZFS is available in FreeBSD as a fully integrated, first class file system and wish to thank all of those who have contributed to it over the years.

by Anne Dickison ( at February 26, 2016 03:23 PM

February 20, 2016

Joseph Koshy

ELF Toolchain v0.7.1

I am pleased to announce the availability of version 0.7.1 of the software being developed by the ElfToolChain project.

This release offers:
  • Better support of the DWARF4 format.
  • Support for more machine architectures.
  • Many bug fixes and improvements.
The release also contains experimental code for:
  • A library handling the Portable Executable (PE) format.
  • A link editor.
The release may be downloaded from SourceForge:
Detailed release notes are available at the URL mentioned above.

Many thanks to the project's supporters for their contributions to the project.

by Joseph Koshy ( at February 20, 2016 12:06 PM

January 25, 2015

Giorgios Keramidas

Some Useful RCIRC Snippets

I have started using rcirc as my main IRC client for a while now, and I really like the simplicity of its configuration. All of my important IRC options now fit in a couple of screens of text.

All the rcirc configuration options are wrapped in an eval-after-load form, to make sure that rcirc settings are there when I need them, but they do not normally cause delays during the startup of all Emacs instances I may spawn:

(eval-after-load "rcirc"


     (message "rcirc has been configured.")))

The “rcirc-setup-forms” are then separated in three clearly separated sections:

  • Generic rcirc configuration
  • A hook for setting up nice defaults in rcirc buffers
  • Custom rcirc commands/aliases

Only the first set of options is really required. Rcirc can still function as an IRC client without the rest of them. The rest is there mostly for convenience, and to avoid typing the same setup commands more than once.

The generic options I have set locally are just a handful of settings to set my name and nickname, to enable logging, to let rcirc authenticate to NickServ, and to tweak a few UI details. All this fits nicely in 21 lines of elisp:

;; Identification for IRC server connections
(setq rcirc-default-user-name "keramida"
      rcirc-default-nick      "keramida"
      rcirc-default-full-name "Giorgos Keramidas")

;; Enable automatic authentication with rcirc-authinfo keys.
(setq rcirc-auto-authenticate-flag t)

;; Enable logging support by default.
(setq rcirc-log-flag      t
      rcirc-log-directory (expand-file-name "irclogs" (getenv "HOME")))

;; Passwords for auto-identifying to nickserv and bitlbee.
(setq rcirc-authinfo '(("freenode"  nickserv "keramida"   "********")
                       ("grnet"     nickserv "keramida"   "********")))

;; Some UI options which I like better than the defaults.
(rcirc-track-minor-mode 1)
(setq rcirc-prompt      "»» "
      rcirc-time-format "%H:%M "
      rcirc-fill-flag   nil)

The next section of my rcirc setup is a small hook function which tweaks rcirc settings separately for each buffer (both channel buffers and private-message buffers):

(defun keramida/rcirc-mode-setup ()
  "Sets things up for channel and query buffers spawned by rcirc."
  ;; rcirc-omit-mode always *toggles*, so we first 'disable' it
  ;; and then let the function toggle it *and* set things up.
  (setq rcirc-omit-mode nil)
  (set (make-local-variable 'scroll-conservatively) 8192))

(add-hook 'rcirc-mode-hook 'keramida/rcirc-mode-setup)

Finally, the largest section of them all contains definitions for some custom commands and short-hand aliases for stuff I use all the time. First come a few handy aliases for talking to ChanServ, NickServ and MemoServ. Instead of typing /quote nickserv help foo, it’s nice to be able to just type /ns help foo. This is exactly what the following three tiny forms enable, by letting rcirc know that “/cs”, “/ms” and “/ns” are valid commands and passing-along any arguments to the appropriate IRC command:

;; Handy aliases for talking to ChanServ, MemoServ and NickServ.

(defun-rcirc-command cs (arg)
  "Send a private message to the ChanServ service."
  (rcirc-send-string process (concat "CHANSERV " arg)))

(defun-rcirc-command ms (arg)
  "Send a private message to the MemoServ service."
  (rcirc-send-string process (concat "MEMOSERV " arg)))

(defun-rcirc-command ns (arg)
  "Send a private message to the NickServ service."
  (rcirc-send-string process (concat "NICKSERV " arg)))

Next comes a nifty little /join replacement which can join multiple channels at once, as long as their names are separated by spaces, commas or semicolons. To make its code more readable, it’s split into 3 little functions: rcirc-trim-string removes leading and trailing whitespace from a string, rcirc-normalize-channel-name prepends “#” to a string if it doesn’t have one already, and finally rcirc-cmd-j uses the first two functions to do the interesting bits:

(defun rcirc-trim-string (string)
  "Trim leading and trailing whitespace from a string."
  (replace-regexp-in-string "^[[:space:]]*\\|[[:space:]]*$" "" string))

(defun rcirc-normalize-channel-name (name)
  "Normalize an IRC channel name. Trim surrounding
whitespace, and if it doesn't start with a ?# character, prepend
one ourselves."
  (let ((trimmed (rcirc-trim-string name)))
    (if (= ?# (aref trimmed 0))
      (concat "#" trimmed))))

;; /j CHANNEL[{ ,;}CHANNEL{ ,;}CHANNEL] - join multiple channels at once
(defun-rcirc-command j (arg)
  "Short-hand for joining a channel by typing /J channel,channel2,channel,...

Spaces, commas and semicolons are treated as channel name
separators, so that all the following are equivalent commands at
the rcirc prompt:

    /j demo;foo;test
    /j demo,foo,test
    /j demo foo test"
  (let* ((channels (mapcar 'rcirc-normalize-channel-name
                           (split-string (rcirc-trim-string arg) " ,;"))))
    (rcirc-join-channels process channels)))

The last short-hand command lets me type /wii NICK to get “extended” whois information for a nickname, which usually includes idle times too:

;; /WII nickname -> /WHOIS nickname nickname
(defun-rcirc-command wii (arg)
  "Show extended WHOIS information for one or more nicknames."
  (dolist (nickname (split-string arg " ,"))
    (rcirc-send-string process (concat "WHOIS " nickname " " nickname))))

With that, my rcirc setup is complete (at least in the sense that I can use it to chat with my IRC friends). There are no fancy bells and whistles like DCC file transfers, or fancy color parsing, and similar things, but I don’t need all that. I just need a simple, fast, pretty IRC client, and that’s exactly what I have now.

by keramida at January 25, 2015 08:41 AM

January 07, 2015

Murray Stokely

AsiaBSDCon 2014 Videos Posted (6 years of BSDConferences on YouTube)

Sato-san has once created a playlist of videos from AsiaBSDCon. There were 20 videos from the conference held March 15-16, 2014 and papers can be found here. Congrats to the organizers for running another successful conference in Tokyo. A full list of videos is included below. Six years ago when I first created this channel videos longer than 10 minutes couldn't normally be uploaded to YouTube and we had to create a special partner channel for the content. It is great to see how the availability of technical video content about FreeBSD has grown in the last six years.

by Murray ( at January 07, 2015 11:22 PM

December 26, 2013

Giorgios Keramidas

Profiling is Our Friend

I recently wrote a tiny demo program to demonstrate to co-workers how one can build a cache with age-based expiration of its entries, using purely immutable Scala collections. The core of the cache was something like 25-30 lines of Scala code like this:

class FooCache(maxAgeMillis: Long) {
  def now: Long = System.currentTimeMillis

  case class CacheEntry(number: Long, value: Long,
                        birthTime: Long) {
    def age: Long = now - birthTime

  lazy val cache: AtomicReference[Hashmap[Long, CacheEntry]] =
    new AtomicReference(HashMap[Long, CacheEntry]]())

  def values: Hashmap[Long, CacheEntry] =
    cache.get.filter{ (key, entry) =>
      entry.age <= maxAgeMillis }

  def get(number: Long): Long = {
    values.find{ case (key, entry) =>
      key == number && entry.age <= maxAgeMillis
    } match {
      case Some((key, entry)) =>
        entry.value                // cache hit
      case _ =>
        val entry = CacheEntry(number, compute(number), now)
        cache.set(values + (number -> entry))

  def compute(number: Long): Long =
    { /* Some long-running computation based on 'number' */ }

The main idea here is that we keep an atomically updated reference to an immutable HashMap. Every time we look for entries in the HashMap we check if (entry.age <= maxAgeMillis), to skip over entries which are already too old to be of any use. Then on cache insertion time we go through the ‘values’ function which excludes all cache entries which have already expired.

Note how the cache itself is not ‘immutable’. We are just using an immutable HashMap collection to store it. This means that Scala can do all sorts of optimizations when multiple threads want to iterate through all the entries of the cache looking for something they want. But there’s an interesting performance bug in this code too…

It’s relatively easy to spot once you know what you are looking for, but did you already catch it? I didn’t. At least not the first time I wrote this code. But I did notice something was ‘odd’ when I started doing lookups from multiple threads and looked at the performance stats of the program in a profiler. YourKit showed the following for this version of the caching code:

JVM Profile #1

See how CPU usage hovers around 60% and we are doing a hefty bunch of garbage collections every second? The profiler quickly led me to line 17 of the code pasted above, where I am going through ‘values’ when looking up cache entries.

Almost 94% of the CPU time of the program was spent inside the .values() function. The profiling report included this part:

|                           Name                            | Time   | Time |
|                                                           | (ms)   | (%)  |
| demo.caching                                              | 62.084 | 99 % |
| +-- d.caching.Numbers.check(long)                         | 62.084 | 99 % |
|   +-- d.caching.FooCacheModule$FooCache.check(long)       | 62.084 | 99 % |
|     +---d.caching.FooCacheModule$FooCache.values()        | 58.740 | 94 % |
|     +---scala.collection.AbstractIterable.find(Function1) |  3.215 |  5 % |

We are spending far too much time expiring cache entries. This is easy to understand why with a second look at the code of the get() function: every cache lookup does old entry expiration and then searches for a matching cache entry.

The way cache-entry expiration works with an immutable HashMap as the underlying cache entry store is that values() iterates over the entire cache HashMap, and builds a new HashMap containing only the cache entries which have not expired. This is bound to take a lot of procesisng power, and it’s also what’s causing the creation of all those ‘new’ objects we are garbage collecting every second!

Do we really need to construct a new cache HashMap every time we do a cache lookup? Of course not… We can just filter the entries while we are traversing the cache.

Changing line 17 from values.find{} to cache.get.find{} does not do cache-entry expiration at the time of every single lookup, and now our cache lookup speed is not limited by how fast we can construct new CacheEntry objects, link them to a HashMap and garbage-collect the old ones. Running the new code through YourKit once more showed an immensely better utilization profile for the 8 cores of my laptop’s CPU:

JVM Profile #2

Now we are not spending a bunch of time constructing throw-away objects, and garbage collector activity has dropped by a huge fraction. We can also make much more effective use of the available CPU cores for doing actual cache lookups, instead of busy work!

This was instantly reflected at the metrics I was collecting for the actual demo code. Before the change, the code was doing almost 6000 cache lookups per second:

-- Timers -------------------------------
             count = 4528121
         mean rate = 5872.91 calls/second
     1-minute rate = 5839.87 calls/second
     5-minute rate = 6053.27 calls/second
    15-minute rate = 6648.47 calls/second
               min = 0.29 milliseconds
               max = 10.25 milliseconds
              mean = 1.34 milliseconds
            stddev = 1.45 milliseconds
            median = 0.62 milliseconds
              75% <= 0.99 milliseconds
              95% <= 4.00 milliseconds
              98% <= 4.59 milliseconds
              99% <= 6.02 milliseconds
            99.9% <= 10.25 milliseconds

After the change to skip cache expiration at cache lookup, and only do cache entry expiration when we are inserting new cache entries, the same timer reported a hugely improved speed for cache lookups:

-- Timers -------------------------------
             count = 27500000
         mean rate = 261865.50 calls/second
     1-minute rate = 237073.52 calls/second
     5-minute rate = 186223.68 calls/second
    15-minute rate = 166706.39 calls/second
               min = 0.00 milliseconds
               max = 0.32 milliseconds
              mean = 0.02 milliseconds
            stddev = 0.02 milliseconds
            median = 0.02 milliseconds
              75% <= 0.03 milliseconds
              95% <= 0.05 milliseconds
              98% <= 0.05 milliseconds
              99% <= 0.05 milliseconds
            99.9% <= 0.32 milliseconds

That’s more like it. A cache lookup which completes in 0.32 milliseconds for the 99-th percentile of all cache lookups is something I definitely prefer working with. The insight from profiling tools, like YourKit, was instrumental in both understanding what the actual problem was, and verifying that the solution actually had the effect I expected it to have.

That’s why profiling is our friend!

by keramida at December 26, 2013 04:38 AM

September 25, 2012

Joseph Koshy

New release: ELF Toolchain v0.6.1

I am pleased to announce the availability of version 0.6.1 of the software being developed by the ElfToolChain project.

This new release supports additional operating systems (DragonFly BSD, Minix and OpenBSD), in addition to many bug fixes and documentation improvements.

This release also marks the start of a new "stable" branch, for the convenience of downstream projects interested in using our code.

Comments welcome.

by Joseph Koshy ( at September 25, 2012 02:25 PM