Set Linux hostname from the device tree

Some embedded boards are manufactured in quantity. In a such situation it’s common to require that each board is uniquely identified for production/sales/maintenance tracking. Serial number is a common solution. The question is where to store the serial number ? I usually recommend to store it in the /etc/hostname file because it make it widely available to all applications and will be display in most log files. If the board have something like a network interface, chance are that you need to assign an unique address to it using the device tree. So I wondering if it’s possible set the hostname as a serial number from the device tree too. I was unable to find something like this on the internet, so I started thinking how can I do that.

Adding the ‘hostname‘ node on the device tree is really trivial. Just add the following line in the <board.dts> file corresponding to the hardware:

  hostname = "board-123456";

Then run ‘make <board.dts>’ from the Linux kernel source tree to get a new <board.dtb> file. Once you boot the Linux kernel with this new <board.dtb> file, you must get the ‘hostname‘ entry in the sysfs filesystem. This allow to do this:

# cat /sys/firmware/devicetree/base/hostname
board-123456

The next step is to setup the Linux hostname at boot time to the value of the device tree ‘hostname‘ node. At first I was thinking that this will need a kernel patch since the device tree is maintained into the kernel and that the hostname value is stored into the ‘nodename‘ field of the kernel’s ‘uts‘ namespace. Until I realize that the hostname command will maybe accept to read the /sys/firmware/devicetree/base/hostname file and correctly set the hostname, even is the buffer returned by the sysfs contain a zero byte at the end. I try it and it worked fine:

# hostname -F /sys/firmware/devicetree/base/hostname
# hostname
board-123456

Inspecting the uname call using ‘strace hostname‘ showed that the zero suffix was correctly ignored:

uname({sys="Linux", node="board-123456", ...}) = 0

Since the hostname command is already called early in the system initialization process to set the hostname to the content of the /etc/hostname file, the simplest solution is to replace the /etc/hostname file by a symbolic link to the /sys/firmware/devicetree/base/hostname file:

# ln -fs /sys/firmware/devicetree/base/hostname /etc/

To get this working the sysfs filesystem need to be mounted before the call to the hostname command. Fortunately this is the case at least in Debian jessie using systemd, but I am almost certain that this will also work with systemvinit.

So simple after all. I hope this hack will work on others distributions too.

Advertisements