How to check Linux version with Autoconf? - linux

My program requires at least Linux 2.6.26 (I use timerfd and some other Linux-specific features).
I have an general idea how to write this macro but I don't have enough knowledge about writing test macros for Autoconf. Algorithm:
Run "uname --release" and store output
Parse output and subtract Linux version number (MAJOR.MINOR.MICRO)
Compare version
I don't know how to run command, store output and parse it.
Maybe such macro already exists and it's available (I haven't found any)?

I think you'd be better off detecting the specific functions you need using AC_CHECK_FUNC, rather than a specific kernel version.
This will also prevent breakage if you find yourself cross-compiling at some point in the future

There is a macro for steps 2 (parse) and 3 (compare) version, ax_compare_version. For example:
linux_version=$(uname --release)
AX_COMPARE_VERSION($linux_version, [eq3], [2.6.26],
[AC_MSG_NOTICE([Ok])],
[AC_MSG_ERROR([Bad Linux version])])
Here I used eq3 so that if $linux_version contained additional strings, such as -amd64, the comparison still succeeds. There is a plethora of comparison operators available.

I would suggest you not to check the Linux version number, but for the specific type you need or function. Who knows, maybe someone decides to backport timerfd_settime() to 2.4.x? So I think AC_CANONICAL_TARGET and AC_CHECK_LIB or similar are your friends. If you need to check the function arguments or test behaviour, you'd better write a simple program and use AC_LANG_CONFTEST([AC_LANG_PROGRAM(...)])/AC_TRY_RUN to do the job.

Without going too deep and write autoconf macros properly (which would be preferable anyway) don't forget that configure.ac is basically a shell script preprocessed by m4. So you can write shell commands directly.
# prev. part of configure.ac
if test `uname -r |cut -d. -f1` -lt 2 then; echo "major v. error"; exit 1; fi
if test `uname -r |cut -d. -f2` -lt 6 then; echo "minor v. error"; exit 1; fi
if test `uname -r |cut -d. -f3` -lt 26 then; echo "micro error"; exit 1; fi
# ...
This is just an idea if you want to do it avoiding writing macros for autoconf. This choice is not good, but should work...
The best way is the already suggested one: you should check for features; so, say in a future kernel timerfd is no more available... or changed someway your code is broken... you won't catch it since you test for version.
edit
As user foof says in comments (with other words), it is a naive way to check for major.minor.micro. E.g. 3.5.1 will fail because of 5 being lt 6, but 3.5.1 comes after 2.6.26 so (likely) it should be accepted. There are many tricks that can be used in order to transform x.y.z into a representation that puts each version in its "natural" order. E.g. if we expect x, y, or z won't be greather than 999, we can do something like multiplying by 1000000 major, 1000 minor and 1 micro: thus, you can compare the result with 2006026 as Foof suggested in comment(s).

Related

How can I add an argument for executable linux file

I have a executable linux file called "Fyserver". I want to open it with this arg
./Fyserver --pass 2849
If I don't enter this --pass arg to ELF, then it should exit itself without even running. Is there a way to do this?
NOTE: I don't have the source code of this ELF. I want to do it in bash.
There is no sane way to do what you are asking. You can't add new behavior to a binary without access to the source code or some serious reverse engineering skills.
The usual solution is to create a simple wrapper, i.e. move ./Fyserver to ./Fyserver.real and create a script like
#!/bin/sh
[ "$1" = "--pass" ] || { echo "Syntax: $0 --pass <pass>" >&2; exit 127; }
exec ./Fyserver.real "$#"
The argument checking could arguably be more sophisticated, but this should at least give you an idea of how this is usually handled.
If you really wanted to, I suppose you could write this logic in a compiled language, and embed the original binary within it somehow.

What is the difference between /lib/modules/version and /lib/modules/version+ (plus sign)?

Please help, who know between /lib/modules/version and /lib/modules/version+ (plus sign)
e.g. /lib/modules/3.4.61 and /lib/modules/3.4.61+.
Sorry my weak English and weak Linux (I am newbie).
First, you need to understand the difference between version and release.
Version is a three fields value, like v5.0.1. We can have alternatives for the same version, especially on development.
As real example: Linus is now working to publish Linux v6.0.0. Before pushing it, he is making many 6.0.0 testing versions, we call it release candidates.
He releases each release candidate as v6.0.0rc2, then v6.0.0rc3, and it keeps increasing. The version prefix keeps the same, it only changes the release suffix (rcN). When its good enough, we releases the 'official' v6.0.0.
So, release is kind of 'version of a version'. Its a very specific moment/commit.
We can check version and release strings using make -s kernelversion and make -s kernelrelease.
kernelrelease is just kernelversion concatenated with a release suffix.
Kernelversion is extracted from the file ./Makefile, from its first lines:
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 0
SUBLEVEL = 0
EXTRAVERSION =
Kernelversion is just these three first values separated by '.'.
Lets see ./scripts/setlocalversion algorithm, he is the guy who tells its release suffix:
if [ -z "$(git describe --exact-match 2>/dev/null)" ]; then
...
if $short; then
echo "+"
return
fi
...
fi
Note that he checks git describe, if it doesn't return an annoted tag, it will return "+". That means, if the version is '6.0.0', it will become '6.0.0+'.
TUTORIAL
First thing we need, is to asure we have a git annoted tag, to avoid the '+'.
Use
git tag -a mytag -m 'Commenting about this tag'
Now ./scripts/setlocalversion may return nothing (empty).
Enable auto complement on .config.
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
Make a file .scmversion with the suffix you want (if you want any).
echo 'mysuffix' > .scmversion
Now check it again with make -s kernelrelease. Its expected to be solved :)

Is there a simple alternative to "who am i" and "logname"?

I noticed that RHEL 8 and Fedora 30 don't update the utmp file properly.
As a result, commands such as 'who am i', 'last', 'w' etc print incorrect results (who am i actually doesn't print anything)
After a bit of googling, I found 'logname' which worked in this case but I read that gnome is dropping support for utmp altogether so it's a matter of time until this stops working too.
I wrote the following script which finds the login name of the user (even if he is using sudo the moment he runs the command) but it's way too complicated so I'm looking for alternatives.
LOGIN_UID=$(cat /proc/self/loginuid)
LOGIN_NAME=$(awk -v val=LOGIN_UID -F ":" '$3==val{print $1}' /etc/passwd)
Is there a simple alternative which is not based on proper updating of /var/run/utmp ?
Edit 1: Solutions that don't work $HOME, $USER and id return incorrect values when used in a script that has been run with the sudo command. who am i and logname depend on utmp which isn't always updated by the terminal.
Working solution: After a bit of searching, a simpler way than the aforementioned was found in https://unix.stackexchange.com/users/5685/frederik-deweerdt 's comment to his own answer
Link to answer which contains the commment: https://unix.stackexchange.com/a/74312
Answer 1
stat -c "%U" $(tty)
Second answer found at https://stackoverflow.com/a/51765389/10630167
Answer 2
`pstree -lu -s $$ | grep --max-count=1 -o '([^)]*)' | head -n 1 | sed 's/[()]//g'`
Your question is not well-defined because if X and Y are not working, what are the chances that Z will work? This depends entirely on the precise failure mode you are attempting to handle, and there is nothing in your question to reveal the specific circumstances in which you need this.
With that out of the way, perhaps look at the POSIX id command, which has explicit options to print the real (login) or effective (after any setuid command) user id with -r or -u, respectively. Of course, the precise means by which it obtains this information are not specified, and will remain implementation-dependent, and thus might or might not work on your platform under your specific circumstances.
As an aside, here is a refactoring of your code to avoid polluting the variable name space with two separate variables.
LOGIN_NAME=$(awk 'NR==FNR { val=$0; next }
$3==val{print $1}' /proc/self/loginuid FS=":" /etc/passwd)

How do I script a "yes" response for installing programs?

I work with Amazon Linux instances and I have a couple scripts to populate data and install all the programs I work with, but a couple of the programs ask:
Do you want to continue [Y/n]?
and pause the install. I want to auto answer "Y" in all cases, I'm just now sure how to do it.
The 'yes' command will echo 'y' (or whatever you ask it to) indefinitely. Use it as:
yes | command-that-asks-for-input
or, if a capital 'Y' is required:
yes Y | command-that-asks-for-input
If you want to pass 'N' you can still use yes:
yes N | command-that-asks-for-input
echo y | command should work.
Also, some installers have an "auto-yes" flag. It's -y for apt-get on Ubuntu.
You might not have the ability to install Expect on the target server.
This is often the case when one writes, say, a Jenkins job.
If so, I would consider something like the answer to the following on askubuntu.com:
https://askubuntu.com/questions/338857/automatically-enter-input-in-command-line
printf 'y\nyes\nno\nmaybe\n' | ./script_that_needs_user_input
Note that in some rare cases the command does not require the user to press enter after the character. in that case leave the newlines out:
printf 'yyy' | ./script_that_needs_user_input
For sake of completeness you can also use a here document:
./script_that_needs_user_input << EOF
y
y
y
EOF
Or if your shell supports it a here string:
./script <<< "y
y
y
"
Or you can create a file with one input per line:
./script < inputfile
Again, all credit for this answer goes to the author of the answer on askubuntu.com, lesmana.
You just need to put -y with the install command.
For example: yum install <package_to_install> -y
Although this may be more complicated/heavier-weight than you want, one very flexible way to do it is using something like Expect (or one of the derivatives in another programming language).
Expect is a language designed specifically to control text-based applications, which is exactly what you are looking to do. If you end up needing to do something more complicated (like with logic to actually decide what to do/answer next), Expect is the way to go.
If you want to just accept defaults you can use:
\n | ./shell_being_run

What is a reliable way to determine which shared library will be loaded across linux platforms?

I need to find out which library will be loaded given in the information returned from /sbin/ldconfig. I came up with the following:
#!/bin/bash
echo $(dirname $(/sbin/ldconfig -p | awk "/$1/ {print \$4}" | head -n 1))
Running this results with:
$ whichlib libGL.so
/usr/X11R6/lib
This a two part question:
Will this produce a reliable result across platform?
Is there a slicker way to parse the output of ldconfig?
Thanks,
Paul
There're several ways the library is loaded by executeable:
1.
Using $LD_LIBRARY_PATH
Using ld cache
Libary with full path compiled into binary (-rpath gcc flag)
You're using option 2, while option 1 and 3 are not considered.
Depending on what exactly you're doing you may want to run ldd directly on the executable you're planning to run rather than the general case ldconfig.
Since you asked, you could write your script like this:
dirname "$(/sbin/ldconfig -p | awk "\$1 == "$1" {print \$4; exit}")"
It's a little more precise and has one less pipe. Also echo $(cmd) is redundant; you can just write cmd.

Resources