How to display IP at login screen in Arch Linux

3

1

I was able to do in Ubuntu by editing the file:

/etc/rc.local

and add:

IP=$(/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}')

echo "IP: $IP" > /etc/issue

In Arch, this file does not exist "/etc/rc.local" and after some search I found that I have to create this file:

/etc/systemd/system/rc-local.service

Content:

[Unit]
Description=/etc/rc.local compatibility

[Service]
Type=oneshot
ExecStart=/etc/rc.local

TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99

[Install]
WantedBy=multi-user.target

Then Create "/etc/rc.local".

Content:

IP=$(/sbin/ip route get 1 | awk '{print $NF;exit}')
echo "IP: $IP" > /etc/issue

exit 0

Then Make it Executable:

sudo chmod +x /etc/rc.local

And finally start/test:

sudo systemctl start rc-local.service

Getting the error:

Job for rc-local.service failed because the control process exited with error code.
See "systemctl status rc-local.service" and "journalctl -xe" for details.

Output of systemctl status rc-local.service:

* rc-local.service - /etc/rc.local Compatibility
Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Fri 2016-06-10 02:52:17 AST; 1min 59s ago
Process: 760 ExecStart=/etc/rc.local (code=exited, status=203/EXEC)

Jun 10 02:52:17 maro systemd[1]: Starting /etc/rc.local Compatibility...
Jun 10 02:52:17 maro systemd[1]: rc-local.service: Control process exited, code=exited status=203
Jun 10 02:52:17 maro systemd[1]: Failed to start /etc/rc.local Compatibility.
Jun 10 02:52:17 maro systemd[1]: rc-local.service: Unit entered failed state.
Jun 10 02:52:17 maro systemd[1]: rc-local.service: Failed with result 'exit-code'.

Output of journalctl -xe:

-- Unit rc-local.service has begun starting up.
Jun 10 02:52:17 maro systemd[760]: rc-local.service: Failed at step EXEC spawning /etc/rc.local: Exec format error
-- Subject: Process /etc/rc.local could not be executed
-- Defined-By: systemd

Update:

  1. Added #!/bin/bash to /etc/rc.local
  2. sudo systemctl daemon-reload
  3. sudo systemctl start rc-local.service
  4. Now I am not getting any errors! but:
  5. sudo systemctl status rc-local.service Output:

    rc-local.service - /etc/rc.local Compatibility Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: disabled) Active: inactive (dead) since Fri 2016-06-10 13:13:04 AST; 3s ago Process: 488 ExecStart=/etc/rc.local (code=exited, status=0/SUCCESS)

    Jun 10 13:13:04 maro systemd[1]: Starting /etc/rc.local Compatibility... Jun 10 13:13:04 maro systemd[1]: Started /etc/rc.local Compatibility.

Tried to reboot and before login it says:

rtnetlink answers network is unreachable

At Login screen: it shows "IP:" only without showing the machine IP. Once logging in and ping google for example, internet is working with no problem and machine is accessible over LAN.


  1. sudo env -i /etc/rc.local = No output
  2. ip route get 1 | awk '{print $NF;exit}' which is used in /etc/rc.local = 192.168.0.103

Output of nav:

XDG_SESSION_ID=c2
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=192.168.0.100 64436 22
SSH_TTY=/dev/pts/0
USER=maro
MAIL=/var/spool/mail/maro
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
PWD=/home/maro
LANG=C
SHLVL=1
HOME=/home/maro
LOGNAME=maro
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
SSH_CONNECTION=192.168.0.100 64436 192.168.0.103 22
XDG_RUNTIME_DIR=/run/user/1000
_=/usr/bin/env

Edited /etc/systemd/system/rc-local.service: Removed four settings after ExecStart. I have also tried changing: Type=forking

Status still saying: Active: inactive (dead)

Maro

Posted 2016-06-10T00:12:18.103

Reputation: 33

It appears that you are wanting to display the IP address, not the IP, as you asked for in the question. You only have two possible IPs: IPv4 and IPv6. – Ron Maupin – 2016-06-10T00:29:34.147

@RonMaupin, Sorry for the mistake, I want to display the internal IP address. Is there any mistake in my steps or bash code? – Maro – 2016-06-10T01:49:34.410

Answers

0

I'm 99% sure it's because you haven't called out the interpreter in the script.

/etc/rc.local:

#!/bin/bash

IP=$(/sbin/ip route get 1 | awk '{print $NF;exit}')
echo "IP: $IP" > /etc/issue

exit 0

That will likely work. Many people also explicitly call out bash in their system file; I've modified your service file. I mention this below, but 4 of the settings are unnecessary (to the best of my knowledge) and I've removed them here as well:

/etc/systemd/system/rc-local.service:

[Unit]
Description=/etc/rc.local compatibility

[Service]
Type=oneshot
ExecStart=/bin/bash /etc/rc.local

[Install]
WantedBy=multi-user.target

You should use the full path to awk as well, but that would be a different error - you haven't gone that far into the script yet.

If that didn't fix it, you'll have to step through each piece of it and see what works by itself. The systemd environment is very sparse (similar to things launched from cron, but less of an environment). Things that always work stop working because of some environmental setting that is always set so we forget that it even needs to be set. So try isolating for an issue related to that. Here are a few isolation steps:

  1. Directly execute (with sudo or in a root shell for each step) /etc/rc.local from a terminal.

  2. If that works, then try executing it as env -i /etc/rc.local If it doesn't work, you can try passing in environmental values one at a time, or have your script 'brute' force set them (highly frowned upon, but you if you were so inclined you could dump the output of env in a 'normal' shell, env | sed 's/^/export /g' | sed 's/=/='/g' | sed -e 's/$/'/g' > env_values.sh and explicitly set those values in the script.. You do need to scrub the list a bit - it will have ssh connection values and other event driven entries that probably won't break anything but definitely won't help anyting).

  3. If it's not that because no matter how you execute rc.local it just works, I would strip back your systemd service file. Try it without them.

    • The remains after exit setting is not relevant here - that is related to using this to call a one time script that spawns daemons.
    • The tty setting is very special case, and is not needed.
    • The timeout setting of 0 can result in hung systems during power cycling.
    • SysVStartPriority is deprecated on systemd ver > 218+; arch is on at least ver 229.
  4. Try using an @reboot cronjob. Very similar environment, but I find it less 'finicky'. @reboot replaces the normal 5 asterisk timing method (e.g. instead of 0 0 0 * * you simply put @reboot), and your script will get called each boot up. If you need additional assistance with setting up a cronjob I can definitely provide more detail.

There is nothing I can see wrong with your method at getting your lan IP. Here is a different method to try if it causes any issues. Yours is probably better. has less dependencies and certainly cleaner, but i've been using this approach for years without issue:

iprgx='(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
cat /etc/hostname | /usr/bin/host -4r | grep -Eo "$iprgx"

If all that fails, then you'll have to read the systemd documentation...which as you've likely discovered is very long on word count and incredibly low on specific information. Let me know what you find out even if it these ideas don't work - there may be a clue in the results regardless.

Update

According to your update, the changes to the service allow the script to run properly. The status you are getting is normal for a one-off - systemd services are really focused around daemon processes that are kicked off, and you aren't doing that - so (simplifying it a lot) basically it saying it's inactive simply means that script isn't still running, it isn't scheduled to run, and it didn't spawn any processes that systemd is tracking - which is all correct and fine. The fact that it shows that it just recently ran and exited with SUCCESS means that it is working.

The second issue is relative timing. The brief answer is that you'll need to change your service file by adding the following two entries under [Unit]. This might just work. If not, read on.

[Unit]
Wants=network-online.target
After=network-online.target

There is an excellent write up on this specific issue on stackexchange They seem to have covered every way that can go wrong and ways it can go right in a wrong way... I won't bother trying to relay it - just get it straight from an apparent guru.

Alternate approach that has the benefit of making systemd fans angry

If that approach becomes difficult or impossible for whatever reason, here's a far less elegent brute force method that I usually turn to when my systemd patience has burned out:

You can modify your script to wait for the IP address to become available itself rather than get tangled in the comes before / comes after timing issues. It's a hack because it's intentionally reimplementing capability that is built into systemd, but this is what I would likely do.

I updated this script (tried running it and found a couple issues). This one works fine on my system. I had used C function syntax on the sleep call, and forget to actually return anything from getIP; both fixed.

/etc/rc.local

#!/bin/bash   

iprgx='(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'

# I put this into a function since you will be looping on it.
# the error you are seeing is from the ip call - I pipe the error to
# /dev/null to get rid of that annoyance.
getIP() {
  echo "IP=$(/sbin/ip route get 1 2>/dev/null | awk '{print $NF;exit}' | grep -Eo "$iprgx")"
}

# watchdog timer - bail if it doesn't resolve after some delta-T
wdTimer=1
IP=$(getIP)
#echo "($wdTimer) IP: $IP"
while [ "$IP" == "" ]; do
  # There's nothing special about .5 seconds - just seemed reasonable
  sleep 0.5
  IP=$(getIP)
  #echo "($wdTimer) IP: $IP"
  ((wdTimer++))
  # Arbitrarily chosen timeout of 20 * 0.5 = 10 seconds
  # You can have it wait as long as you want. I suggest not
  # setting the sleep time too low as you'll be hammering on the
  # ip utility fairly hardly in that case; not a huge deal regardless
  # I also had it log something to the syslog - your mileage may vary
  # with logger - there are alternative ways to do that.
  if [ "$wdTimer" -gt "20" ]; then
    # timeout
    logger -s "Timed out attempting to acquire LAN IP in rc.local"
    exit 1
  fi
done
#echo "IP: $IP" #> /etc/issue
exit 0

And yes, I use that regex $iprgx all the time - super helpful.

Argonauts

Posted 2016-06-10T00:12:18.103

Reputation: 4 000

I really appreciate your great response, I have tried it and posted the results in my question for a better formatting. – Maro – 2016-06-10T11:33:27.933

I figured there would be problems hidden behind the first one. So the script is running now; it's just running too early at boot. I'm putting more info in my answer – Argonauts – 2016-06-10T12:03:18.383

There isn't any errors now but when I check the status it says: Active: inactive (dead) 3s ago, could it stay active/running for some minutes for example? so it solve the issue? – Maro – 2016-06-10T12:20:19.063

You asked this question before I had updated the answer where I tried to clarify that a bit. Basically the status you are seeing (inactive (dead) is expected, normal behavior for a oneshot service. It's done it's thing, it hasn't daemonized, it has no restart, stop etc. capabilities; so it is accurately called dead. The take away is that it ran successfully - for this type of oneshot that 'SUCCESS' is the most relevent info. – Argonauts – 2016-06-10T12:33:02.893

Thank you so much for every second you took to write your answer, helped me a lot. the two lines after the [Unit] solved it! Many Thanks – Maro – 2016-06-10T12:44:22.750

great - i was trying to fix a script you didn't need! After seeing the length of the method to properly time things in that answer, I wasn't optimistic it would be smooth. Enjoy. – Argonauts – 2016-06-10T12:46:34.850

3

On CentOS 7 and Debian 8 (and maybe other as well), just append the following line to /etc/issue

My IP address: \4

and that will resolve to the machine's IPv4 address. If you have multiple network interfaces and you want to pick one specific, you can specify it with

My IP address: \4{eth0}

PaoloC

Posted 2016-06-10T00:12:18.103

Reputation: 201