How do I get a symlinked /etc/hostname to take effect at boot

2.9k views Asked by At

I am working on an embedded Linux device with 3 different Linux partitions. The end use selects which partition to boot from. The root file system is read-only. There is a 4th partition that is mounted read-write. I need all instances of Linux to resister the same name with the DNS server (I.E. use the same host name). The host name is not known when the file system is created and is assigned later due to the fact that each device needs a unique host name. What I have done is create a file on the read-write partition that will get over written at a later date. Then I changed /etc/hostname to be a symlink to that file. I know that the file cannot be read until the read-write partition has been mounted and I believe that is my issue. If I set the /etc/hostname to a normal file then whatever is specified in that file works fine. Changing /etc/hosts does not seem do to anything.

The desired result is to control the name registered with the DNS server when the WiFi connects. The only way I have found to control this is through the host name. The /etc/hosts file does not seem to affect it. If the host name file is unreadable or not set then Linux defaults it to "localhost" and does not register anything useful with the DNS.

The WiFi is enabled through rfkill by an application that is run after boot. Running something in a script before the WiFi is enabled is a possible solution. I have not been able to successfully change what is registered with the DNS by changing the hostname on the command line before the WiFi is enabled. I can get the hostname changed but what is registered with DNS does not change.

Info:

The Linux Kernel is 3.14.60 and is a yocto based build.

systemd manages services on boot.

Current /etc/hosts

127.0.0.1       ABC123.localdomain              ABC123

Current /etc/hostname

SerialNumberGoesHere

Here are all the ways to see the host name after boot:

>hostname
localhost

>hostnamectl status
   Static hostname: SerialNumberGoesHere
Transient hostname: localhost
         Icon name: computer
        Machine ID: 4cdac8e5dce348d2bfc133dd393f6172
           Boot ID: 9b8c9da934e748fc86606c4a24f57f9e
  Operating System: Linux
            Kernel: Linux 3.14.60+g02d9429
      Architecture: arm

>uname -n
localhost

>echo /proc/sys/kernel/hostname
localhost

>sysctl kernel.hostname
kernel.hostname = localhost

As you can see "hostnamectl status" picks up the correct Static hostname, but the kernel did not.

On the Device

>nslookup 192.168.12.238
Server:    192.168.12.6
Address 1: 192.168.12.6 dc1.hq.com

Name:      192.168.12.238
Address 1: 192.168.12.238 linux.local

On another Computer (Ping 192.168.12.238 works)

>nslookup 192.168.12.238
Server:     127.0.1.1
Address:    127.0.1.1#53

** server can't find 238.12.168.192.in-addr.arpa: NXDOMAIN

If I change the hostname symlink to a real file this is the desired result:

>hostname
SerialNumberGoesHere

>hostnamectl status
   Static hostname: SerialNumberGoesHere
         Icon name: computer
        Machine ID: 4cdac8e5dce348d2bfc133dd393f6172
           Boot ID: ed760b42b7ae414881bc2d9352a8bb82
  Operating System: ARANZ Sugar-Free Silhouette Star M2 (fido)
            Kernel: Linux 3.14.60+g02d9429
      Architecture: arm

>uname -n
SerialNumberGoesHere

>echo /proc/sys/kernel/hostname
SerialNumberGoesHere

>sysctl kernel.hostname
kernel.hostname = SerialNumberGoesHere

On the Device

> nslookup 192.168.12.238
Server:    192.168.12.7
Address 1: 192.168.12.7 dc1.hq.com

Name:      192.168.12.238
Address 1: 192.168.12.238 serialnumbergoeshere.hq.com

On another Computer

> nslookup 192.168.12.238
Server:     127.0.1.1
Address:    127.0.1.1#53

238.12.168.192.in-addr.arpa name = serialnumbergoeshere.hq.com.

Update Jan 10, 2017

I found the Answer. You must restart the network service after the hostname command.

systemctl restart systemd-networkd.service

3

There are 3 answers

3
Geoffrey VL On

I was looking for a similar functionality.

My first thought was also to symlink /etc/hostname to a file on another partition, and make sure the partition is mounted before following boot message appears: systemd[1]: Set hostname to <myhostname>.

However, after digger a bit deeper it doesn't come that simple. From what I found elsewhere:

I would have expected that initramfs packs your /etc/hostname with actual hostname, perhaps you need to regenerate initramfs?

systemd is started early in initramfs where it sets hostname from initramfs, but after switching root to actual system it reexecutes and sets hostname again, therefore you should end up with proper hostname anyway

So I ended up with the solution Daniel Schepler provided. Here the systemd service:

[Unit]
Description=Update hostname to what we want
Before=systemd-networkd.target
After=mountdata.service
RequiresMountsFor=/usr
DefaultDependencies=no

[Service]
Type=simple
ExecStart=/usr/bin/mycustomhostnamescript.sh

[Install]
WantedBy=multi-user.target

The script:

...
    hostn=$(cat "$FILE_SERIAL")
    echo "setting hostname=$hostn"
    echo "$hostn" > /etc/hostname
    hostname "$hostn"
...

Its important that you don't use hostnamectl within the script as it will fail due to its dependencies not being loaded yet!

The solution works without needing to restart the networking service since it wasn't started yet. It also works with rebooting only once.

0
Armali On

You must restart the network service after the hostname command.

systemctl restart systemd-networkd.service

– schustercp

0
grahas On

For mender I was able to use

[Unit]
Description=Update hostname to what we want
Before=systemd-networkd.target
After=mountdata.service
RequiresMountsFor=/data
DefaultDependencies=no

[Service]
Type=simple
ExecStart=/usr/bin/hostname -F /etc/hostname

[Install]
WantedBy=multi-user.target

I changed the RequiresMountFor to be my data partition that contains the text file for the hostname.