how to write a bash script that would get minor and major device numbers of /dev/random - linux

I am trying to run a program in a chrooted environment, and it needs /dev/random as a resource.
Manually I can do ls -l on it and then create the file again with mknod c xx yy, but I need to make it automatic and I don't think these version numbers are constant from a linux version to another so that is why I have the following question :
How could I write a bash script that would extract the minor and major numbers of /dev/random and use it with mknod? I can use ls -l but I don't know how to extract a substring of it...
The exact return of ls -l /dev/random is :
crw-rw-rw- 1 root root MINOR, MAJOR mars 30 19:15 /dev/random
and the two numbers I want to extract are MINOR and MAJOR. However if there is an easier way to create the node without ls and mknod I would appreciate it.

You can get the major and minor device numbers with stat:
MINOR=`stat -c %T /dev/random`
MAJOR=`stat -c %t /dev/random`
You can then create a device node with:
mknod mydevice c "$MAJOR" "$MINOR"
Another approach (which doesn't require the parsing of device numbers) is to use tar to create an archive with the details of the device files in:
cd /dev
tar cf /somewhere/devicefiles.tar random null [any other needed devices]
then
cd /somewhere/chroot-location
tar xf /somewhere/devicefiles.tar
This latter method has the advantage that it doesn't rely on the -c option to stat, which is a GNU extension.

A minor improvement to efficiency would be to do only one call (and to use lower-case variable names, as is conventional for all variables other than builtins and environment variables in shell):
read minor major < <(stat -c '%T %t' /dev/random)
On a GNU system, by the way, I'd suggest using cp -a to copy your explicitly whitelisted device files into the chroot during setup:
cp -a /dev/random /your/chroot/dev/random

Try this.
MAJOR=ls -l /dev/random | awk '{ print $5}'
MINOR=ls -l /dev/random | awk '{ print $6}'

Related

How can I extract only an inode number for a file in Linux?

just a quick question. I want to use my inode number in my bash script however, I need some help.
I'm using command ls -i "filename", which echoes "inode number" "filename". The problem is, I only need inode number. Is there a way, where i can "slice" the output?
You can use stat command with %i to get only inode nuymbers:
stat -c '%i' *
Most of the utilities/commands use to get inode use lstat system call which is the one used by stat command too.
you can also awk over the ls
-bash-3.2$ ls -i current.py | awk '{print $1}'

Grep in Ubuntu 14.04

I just recently updated my Ubuntu VM to 14.04 and before this I could run the grep command
grep -nr "piece of text"
or any other grep command for that matter and it would finish in 2-10 seconds in the directory I was working on. Now for some reason (no idea if this was caused by the update) running any grep command in the same dir I was working in just seems to hang there (idk if it does complete because I don't want to wait over a min or so for a search to happen) instead of showing my results. Any idea of what's happening or what I can do and try to fix it?
You aren't specifying the files to grep, so it's trying to read STDIN. I think you wanted
grep -nr "piece of text" *
Note the asterisk is globbed to all files in the current path.
which grep are you using ? -r option default to '.' directory in gnu case
which grep :
/bin/grep --version
/bin/grep (GNU grep) 2.18)
...
this is gnu grep :
echo "truc" >/tmp/truc
cd /tmp; grep -nr "truc";
using gnu grep -> it search recursively files in . of current directory ( here in /tmp ) and displays them containing "truc"
if /bin/grep --version is busybox :
BusyBox v1.22.1 (Debian 1:1.22.0-8) multi-call binary.
Usage:
grep [-HhnlLoqvsriwFEz] [-m N] [-A/B/C N] PATTERN/-e PATTERN.../-f FILE [FILE]...
using busybox : cd /tmp; busybox grep -nr "truc";
wait indefinitely that you type content of file on STDIN ( stop with Ctrl+C ).
it reads STDIN as a file ( not even caring that -n indicates a directory recursion ).
As others answered, and as POSIX grep or GNU grep documentation tells, you need to specify some file to the standard grep command. (But GNU grep defaults to current directory . if -r is given without a directory name; however if -r is not given at all, grep defaults to read - i.e. the stdin).
BTW, I would also recommend the ack utility, packaged as the ack-grep package on Ubuntu or Debian. It does not need any files (default is the source code files under current directory) and it avoids useless non-source files (version control or object files...):
ack "piece of text"
Also, under emacs, you can use M-x grep

How to get CPU serial under Linux without root permissions

How can I get CPU serial number under Linux (Ubuntu) without root permissions?
I tried cpuid command, it works without root permissions, but appears to return all zeros (I believe because something needs to be changed in BIOS).
Can you please suggest me another way to retrieve CPU serial from a program without root permissions and without having to modify BIOS?
Root permissions required. The answer is dmidecode.
If you need CPU ID:
dmidecode | grep -w ID | sed "s/^.ID\: //g"
This will get CPU ID, remove 'ID: ' from output
If you need to receive a computer ID:
dmidecode | grep -w UUID | sed "s/^.UUID\: //g"
If you wish to get kernel uuid without root permissions, then:
dmesg | grep UUID | grep "Kernel" | sed "s/.*UUID=//g" | sed "s/\ ro\ quiet.*//g"
It's because of recent comment. Happened long time ago, so can't explain now why these ID were taken as machine identifier. Got actual Processor ID fromn Processor Information section. Extracted on Debian OS.
pr=0; dmidecode | while read line; do [ "$line" == "Processor Information" ] && pr=1; [ $pr -eq 0 ] && continue; [ -n "$(echo $line | grep '^ID')" ] && echo $line | awk -F"ID: " '{print $2}' && break; done
Processor serial numbers were basically only in Pentium III processors. Intel removed it from later models due to the privacy concerns that were raised. As such, unless you're on a PIII AND your BIOS settings let you read the serial number, all you'll get are 0's.
Tie the license to the inode numbers that its executable files get when they are installed into the user's filesystem. If they are moved somewhere else, they will change.
The downside is that the numbers may not be preserved if the program has to be restored from a backup.
I've done this sort of thing before. You have to be very generous about letting genuine users activate the license on changing hardware.
cpuid returns the same serial number for me regardless of my use of sudo:
% cpuid | grep serial
Processor serial: 0002-0652-0000-0000-0000-0000
% sudo cpuid | grep serial
Processor serial: 0002-0652-0000-0000-0000-0000
Unless there's some other serial number that you're referring to...?
As suggested when this question was asked before, if you are trying to use this for licensing (since you used the licensing tag) you may want to try the MAC address:
CPU serial number
CPUs has no serial number; maybe that you want DMI basic info without root privilege (This will only show you a persistent id of your motherboard manufacturer and model, but no serial number):
dmesg | grep -i dmi: | cut -d ":" -f 2-
Otherwise you could "tell" dmidecode to run from unprivileged user:
sudo chmod +s /usr/sbin/dmidecode
Then you could run for instance:
dmidecode -s system-serial-number
In most cases "system-serial-number" is like either "chassis-serial-number" or "baseboard-serial-number". Remember that not all distros have this program installed, for instance, Debian based systems have a package named after it.
Otherwise you can find a unique and persistent, thro' installs, system ID via your system's disk; to do that you may run the following:
mount | grep "on / type" | awk '{print $1}'
The former will give you device's path where your system is mounted (for my OS it returned /dev/sda7), and then you can find an ID for it with the following:
find /dev/disk/by-id/ -lname "*sda" ! -name "wwn*"
So the complete command to find a unique ID from your system's hard disk could be:
find /dev/disk/by-id/ -lname "*`mount | grep " / " | awk '{print $1}' | cut -b 6-8`" ! -name "wwn*" -printf "%f\n"
I hope this may fit your needs or someone else's in here. Command cut -b 6-8 may not be portable, because I'm assuming block devices names to be three chars long; moreover, /dev/disk/by-id/ path is only filled by UDEV managed systems and not all Linux distros use it, but I ensure you the former will work in Ubuntu.
Have you checked dmesg? Its in /bin

Identify the files opened a particular process on linux

I need a script to identify the files opened a particular process on linux
To identify fd :
>cd /proc/<PID>/fd; ls |wc –l
I expect to see a list of numbers which is the list of files descriptors' number using in the process. Please show me how to see all the files using in that process.
Thanks.
The command you probably want to use is lsof. This is a better idea than digging in /proc, since the command is a more clear and a more stable way to get system information.
lsof -p pid
However, if you're interested in /proc stuff, you may notice that files /proc/<pid>/fd/x is a symlink to the file it's associated with. You can read the symlink value with readlink command. For example, this shows the terminal stdin is bound to:
$ readlink /proc/self/fd/0
/dev/pts/43
or, to get all files for some process,
ls /proc/<pid>/fd/* | xargs -L 1 readlink
While lsof is nice you can just do:
ls -l /proc/pidoftheproces/fd
lsof -p <pid number here> | wc -l
if you don't have lsof, you can do roughly the same using just /proc
eg
$ pid=1825
$ ls -1 /proc/$pid/fd/*
$ awk '!/\[/&&$6{_[$6]++}END{for(i in _)print i}' /proc/$pid/maps
You need lsof. To get the PID of the application which opened foo.txt:
lsof | grep foo.txt | awk -F\ '{print $2}'
or what Macmede said to do the opposite (list files opened by a process).
lsof | grep processName

Give the mount point of a path

The following, very non-robust shell code will give the mount point of $path:
(for i in $(df|cut -c 63-99); do case $path in $i*) echo $i;; esac; done) | tail -n 1
Is there a better way to do this in shell?
Postscript
This script is really awful, but has the redeeming quality that it Works On My Systems. Note that several mount points may be prefixes of $path.
Examples
On a Linux system:
cas#txtproof:~$ path=/sys/block/hda1
cas#txtproof:~$ for i in $(df -a|cut -c 57-99); do case $path in $i*) echo $i;; esac; done| tail -1
/sys
On a Mac OSX system
cas local$ path=/dev/fd/0
cas local$ for i in $(df -a|cut -c 63-99); do case $path in $i*) echo $i;; esac; done| tail -1
/dev
Note the need to vary cut's parameters, because of the way df's output differs; using awk solves this, but even awk is non-portable, given the range of result formatting various implementations of df return.
Answer
It looks like munging tabular output is the only way within the shell, but
df -P "$path" | tail -1 | awk '{ print $NF}'
based on ghostdog74's answer, is a big improvement on what I had. Note two new issues: firstly, df $path insists that $path names an existing file, the script I had above doesn't care; secondly, there are no worries about dereferencing symlinks. This doesn't work if you have mount points with spaces in them, which occurs if one has removable media with spaces in their volume names.
It's not difficult to write Python code to do the job properly.
df takes the path as parameter, so something like this should be fairly robust;
df "$path" | tail -1 | awk '{ print $6 }'
In theory stat will tell you the device the file is on, and there should be some way of mapping the device to a mount point.
For example, on linux, this should work:
stat -c '%m' $path
Always been a fan of using formatting options of a program, as it can be more robust than manipulating output (eg if the mount point has spaces). GNU df allows the following:
df --output=target "$path" | tail -1
Unfortunately there is no option I can see to prevent the printing of a header, so the tail is still required.
i don't know what your desired output is, therefore this is a guess
#!/bin/bash
path=/home
df | awk -v path="$path" 'NR>1 && $NF~path{
print $NF
}'
Using cut with -c is not really reliable, since the output of df will be different , say a 5% can change to 10% and you will miss some characters. Since the mount point is always at the back, you can use fields and field delimiters. In the above, $NF is the last column which is the mount point.
I would take the source code to df and find out what it does besides calling stat as Douglas Leeder suggests.
Line-by-line parsing of the df output will cause problems as those lines often look like
/dev/mapper/VOLGROUP00-logical--volume
1234567 1000000 200000 90% /path/to/mountpoint
With the added complexity of parsing those kinds of lines as well, probably calling stat and finding the mountpoint is less complex.
If you want to use only df and awk to find the filesystem device/remote share or a mount point and they include spaces you can cheat by defining the field separator of awk to be a regular expression that matches the format of the numeric sizes used to display total size, used space, available space and capacity percentage. By defining those columns as the field separator you are then left with $1 representing the filesystem device/remote share and $NF representing the mount path.
Take this for example:
[root#testsystem ~] df -P
Filesystem 1024-blocks Used Available Capacity Mounted on
192.168.0.200:/NFS WITH SPACES 11695881728 11186577920 509303808 96% /mnt/MOUNT WITH SPACES
If you attempt to parse this with the quick and dirty awk '{print $1}' or awk '{print $NF}' you'll only get a portion of the filesystem/remote share path and mount path and that's no good. Now make awk use the four numeric data columns as the field separator.
[root#testsystem ~] df -P "/mnt/MOUNT WITH SPACES/path/to/file/filename.txt" | \
awk 'BEGIN {FS="[ ]*[0-9]+%?[ ]+"}; NR==2 {print $1}'
192.168.0.200:/NFS WITH SPACES
[root#testsystem ~] df -P "/mnt/MOUNT WITH SPACES/path/to/file/filename.txt" | \
awk 'BEGIN {FS="[ ]*[0-9]+%?[ ]+"}; NR==2 {print $NF}'
/mnt/MOUNT WITH SPACES
Enjoy :-)
Edit: These commands are based on RHEL/CentOS/Fedora but should work on just about any distribution.
Just had the same problem. If some mount point (or the mounted device) is sufficent as in my case You can do:
DEVNO=$(stat -c '%d' /srv/sftp/testconsumer)
MP=$(findmnt -n -f -o TARGET /dev/block/$((DEVNO/2**8)):$((DEVNO&2**8-1)))
(or split the hex DEVNO %D with /dev/block/$((0x${DEVNO:0:${#DEVNO}-2})):$((0x${DEVNO:2:2})))
Alternatively the following loop come in to my mind, out of ideas why I cannot find proper basic command..
TARGETPATH="/srv/sftp/testconsumer"
TARGETPATHTMP=$(readlink -m "$TARGETPATH")
[[ ! -d "$TARGETPATHTMP" ]] && TARGETPATHTMP=$(dirname "$TARGETPATH")
TARGETMOUNT=$(findmnt -d backward -f -n -o TARGET --target "$TARGETPATHTMP")
while [[ -z "$TARGETMOUNT" ]]
do
TARGETPATHTMP=$(dirname "$TARGETPATHTMP")
echo "$TARGETPATHTMP"
TARGETMOUNT=$(findmnt -d backward -f -n -o TARGET --target "$TARGETPATHTMP")
done
This should work always but is much more then I expect for such simple task?
(Edited to use readlink -f to allow for non existing files, -m or -e for readlink could be used instead if more components might not exists or all components must exists.)
mount | grep "^$path" | awk '{print $3}'
I missed this when I looked over prior questions: Python: Get Mount Point on Windows or Linux, which says that os.path.ismount(path) tells if path is a mount point.
My preference is for a shell solution, but this looks pretty simple.
I use this:
df -h $path | cut -f 1 -d " " | tail -1
Linux has this, which will avoid problem with spaces:
lsblk -no MOUNTPOINT ${device}
Not sure about BSD land.
f () { echo $6; }; f $(df -P "$path" | tail -n 1)

Resources