Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where does bash prompt escape sequence \h get the hostname from?

\h is a bash prompt escape sequence that expands to the hostname. Where does it get the hostname from? On my system it shows a value that I cannot find anywhere, not in hostname -f or /etc/hosts or /etc/hostname or /etc/sysconfig/network or $HOSTNAME. So I'm wondering where it's getting it from. My system is Centos 7.4. I know there are hidden places where things such as UUIDs are stored, and I seem to recall that I've come across a similar hidden hostname type of issue in the past, but I can't remember the details.

like image 808
Michael Martinez Avatar asked Mar 07 '23 17:03

Michael Martinez


1 Answers

If you look at the bash source code you'll see in shell.c that it calls gethostname(2), a POSIX system call that retrieves the hostname from the kernel.

/* It's highly unlikely that this will change. */
if (current_host_name == 0)
  {
    /* Initialize current_host_name. */
    if (gethostname (hostname, 255) < 0)
      current_host_name = "??host??";
    else
      current_host_name = savestring (hostname);
  }

This is not necessarily a canonical string. The kernel doesn't actually know the machine's network hostname. It just reports back whatever was passed to sethostname(2). To quote from the uname(2) man page:

On the other hand, the [hostname] is meaningless: it gives the name of the present machine in some undefined network, but typically machines are in more than one network and have several names. Moreover, the kernel has no way of knowing about such things, so it has to be told what to answer here.

On non-Linux systems without gethostname(2), bash falls back to uname(2). If uname(2) isn't even available then it simply displays "unknown". You can see that logic in lib/sh/oslib.c:

#if !defined (HAVE_GETHOSTNAME)
#  if defined (HAVE_UNAME)
#    include <sys/utsname.h>
int
gethostname (name, namelen)
     char *name;
     int namelen;
{
  int i;
  struct utsname ut;

  --namelen;

  uname (&ut);
  i = strlen (ut.nodename) + 1;
  strncpy (name, ut.nodename, i < namelen ? i : namelen);
  name[namelen] = '\0';
  return (0);
}
#  else /* !HAVE_UNAME */
int
gethostname (name, namelen)
     char *name;
     int namelen;
{
  strncpy (name, "unknown", namelen);
  name[namelen] = '\0';
  return 0;
}
#  endif /* !HAVE_UNAME */
#endif /* !HAVE_GETHOSTNAME */

\h isn't updated if the hostname changes. The value is cached at startup when the shell is initialized.

[jkugelman@malkovich]$ hostname
malkovich
[jkugelman@malkovich]$ sudo hostname kaufman
[jkugelman@malkovich]$ hostname
kaufman
[jkugelman@malkovich]$ bash
[jkugelman@kaufman]
like image 154
John Kugelman Avatar answered Apr 06 '23 00:04

John Kugelman