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

\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.

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]

It probably (just a guess) uses the gethostname(2) system call (which is handled by the kernel, as all syscalls(2) are...)
BTW, GNU bash is (as most packages of your Linux distributions are) free software; so please download its source code and study it; use the source, Luke! and open the source more, please.
A more interesting question is how that information is cached by bash. Does it call gethostname at every command? You might also use strace(1) to find out.
Of course, take the habit of studying the source code of free software every time you are curious. And use strace -and the gdb debugger- to understand their dynamic behavior.
A French singer, G.Bedos, told us "La liberté ne s'use que si on ne s'en sert pas", that is
Freedom wears out if you don't use it.
(translation is mine, I am French but not a native English speaker)
So next time, please dive into the source code of free software. It is important to exercise your freedom, and that is what free software is about.

Related

How to print source file name with dladdr() function?

I was trying to print a backtrace using dladdr(). info.dli_fname in the following code snippet is displaying the file name of an ELF file. Could you please tell me if it is possible to resolve and print the name of the source file and line number programmatically without the help of addr2line or gdb?
Code:
void print_caller(void)
{
int rc = -1;
Dl_info info = {0};
void *pc = __builtin_return_address(0);
rc = dladdr(pc, &info);
printf(" ==> %p: %s (in %s)\n", pc, info.dli_sname, info.dli_fname);
}
Output:
$ ./a.out
==> 0x55a6b04a1589: foo2 (in ./a.out)
tell me if it is possible to resolve and print the name of the source file and line number programmatically
It is definitely possible -- addr2line and gdb do that.
But it is very non-trivial -- it requires understanding and decoding (possibly multiple) complicated debugging info formats.
If you only care about a single platform (looks like Linux), things are a bit easier -- you only need to decode DWARF.
But that format is still pretty complicated. You should start with a helper library, such as libdwarf.

Setting kernel tunable parameter

As I wanted to introduce new kernel module parameter say new_param=1 /0 ,then after that parameter has to be checked inside kernel code as
if (new_param==1)
do some work.....
else
do other...
In this way I wanted to check by introducing new kernel module parameter.Can anyone please help me? What are the steps I need to follow to do this ?
One way to use a custom kernel parameter is to add it to the kernel command line and parse it out of /proc/cmdline, i.e.:
Add the parameter to the kernel command line
BOOT_IMAGE=<image> root=<root> ro quiet splash vt.handoff=7 your_parameter=<value>
When you boot, you will be able to access this parameter by parsing the contents of /proc/cmdline:
$ cat /proc/cmdline
BOOT_IMAGE=<image> root=<root> ro quiet splash vt.handoff=7 your_parameter=<value>
I believe a solution more tailored to your needs would include using __setup(), which is mentioned (but not explained well) in /Documentation/kernel-parameters.txt.
There are quite a few examples in the kernel source. One of such would be in /drivers/block/brd.c:
#ifndef MODULE
/* Legacy boot options - nonmodular */
static int __init ramdisk_size(char *str)
{
rd_size = simple_strtol(str, NULL, 0);
return 1;
}
__setup("ramdisk_size=", ramdisk_size);
#endif
Following this example, you could add your __init and __setup() in the relevant source file. For parsing integers from an option string in your __init function, see get_option() in /lib/cmdline.c
Update
For modules, you should use module_param(), which takes three arguments: variable name, variable type, sysfs permissions. More on the class is found at /linux/moduleparam.h.
In the module that you want to be able to pass parameters to, first declare the parameters as globals. An example usage would include the following in the module source:
int foo = 200;
module_param(foo, int, 0);
Recompile the module and you will see that you can load it via modprobe <module-name> foo=40.

How to check if a specific program (shell command) is available on a Linux in D?

I am trying to write a script-like D program, that would have different behaviour based on availability of certain tools on user's system.
I'd like to test if a given program is available from command line (in this case it is unison-gtk) or if it is installed (I care only about Ubuntu systems, which use apt)
For the record, there is a walk around using e.g. tryRun:
bool checkIfUnisonGTK()
{
import scriptlike;
return = tryRun("unison-gtk -version")==0;
}
Instead of tryRun, I propose you grab the PATH environment variable, parse it (it is trivial to parse it), and look for specific executable inside those directories:
module which1;
import std.process; // environment
import std.algorithm; // splitter
import std.file; // exists
import std.stdio;
/**
* Use this function to find out whether given executable exists or not.
* It behaves like the `which` command in Linux shell.
* If executable is found, it will return absolute path to it, or an empty string.
*/
string which(string executableName) {
string res = "";
auto path = environment["PATH"];
auto dirs = splitter(path, ":");
foreach (dir; dirs) {
auto tmpPath = dir ~ "/" ~ executableName;
if (exists(tmpPath)) {
return tmpPath;
}
}
return res;
} // which() function
int main(string[] args) {
writeln(which("wget")); // output: /usr/bin/wget
writeln(which("non-existent")); // output:
return 0;
}
A natural improvement to the which() function is to check whether tmpPath is an executable, or not, and return only when it found an executable with given name...
There can't be any «native D solution» because you are trying to detect something in the system environment, not inside your program itself. So no solution will be «native».
By the way, if you are really concerned about Ubuntu only, you can parse output of command dpkg --status unison-gtk. But for me it prints that package 'unison-gtk' is not installed and no information is available (I suppose that I don't have enabled some repo that you have). So I think that C1sc0's answer is the most universal one: you should try to run which unison-gtk (or whatever the command you want to run is) and check if it prints anything. This way will work even if user has installed unison-gtk from anywhere else than a repository, e.g. has built it from source or copied a binary directly into /usr/bin, etc.
Linux command to list all available commands and aliases
In short: run auto r = std.process.executeShell("compgen -c"). Each line in r.output is an available command. Requires bash to be installed.
man which
man whereis
man find
man locate

Astyle does not work in Windows

I just download Astyle from SourceForge. When I execute Astyle.exe in /bin, it said
Cannot convert to multi-byte string, reverting to English.
I don't know what happened.
I find there is a similar question, but that is about Astyle in OS X.
Here are the source code related to the error. I don't know the meaning of the second line.
// Not all compilers support the C++ function locale::global(locale(""));
// For testing on Windows change the "Region and Language" settings or use AppLocale.
// For testing on Linux change the LANG environment variable: LANG=fr_FR.UTF-8.
// setlocale() will use the LANG environment variable on Linux.
char* localeName = setlocale(LC_ALL, "");
if (localeName == NULL) // use the english (ascii) defaults
{
fprintf(stderr, "\n%s\n\n", "Cannot set native locale, reverting to English");
setTranslationClass();
return;
}
Finally, please feel free to correct my English.
Add following include to both ASLocalizer.cpp and style_main.cpp:
<#include "locale.h">

Get current system local encoding in Perl on Windows

I need to get the current encoding according to the system local settings. I'm looking for such function working this way:
my $sysEncoding = getSystemEncoding();
#and now $sysEncoding equals e.g. 'windows-1250'
I looked everywhere on the internet. I've found just the module PerlIO::locale. But I thing that the system encoding should be recognized easier without additional modules.
Encode::Locale provides the means to handle this.
use Win32::API;
if (Win32::API->Import('kernel32', 'int GetACP()')) {
$enc = GetACP();
print "Current local encoding is '$enc'\n";
}
Thanks for hint to Ikegami.

Resources