My linux bash $$ doesn't match /proc/self link? - linux

I'm on RHEL 5 and tried /proc like this:
$echo $$
50040
$ls -ld /proc/self
lrwxrwxrwx 1 root root 64 Jan 22 15:25 /proc/self -> 22485
I expected that /proc/self link to a subdirectory of /proc that's my current process id. But $$ shows process id is 50040, not 22485. Why is that?

The PID you are seeing when issuing the ls command is the one for the ls command, not that of your shell. If you do it many times in a row, you will see it is different each time:
fred> ls -ld /proc/self
lrwxrwxrwx 1 root root 0 Jan 12 13:13 /proc/self -> 5075
fred> ls -ld /proc/self
lrwxrwxrwx 1 root root 0 Jan 12 13:13 /proc/self -> 5076
fred> ls -ld /proc/self
lrwxrwxrwx 1 root root 0 Jan 12 13:13 /proc/self -> 5077
If you want to get the PID of the shell, you need to make sure you use /proc/self when the shell is running, not one of its sub-processes:
cd /proc/self ; pid=$(awk '{print $1}' stat) ; cd -
(the cd is a bash internal command so, at the point where you access /proc/self, you're still running in the shell process itself).

Check out man proc. The /proc/self refers to the process accessing the /proc filesystem and not the id of the shell (which is what $$ is returning and would be the parent of /proc/self).

Related

setuid on echo command but not working as expected

I have a question about setuid:
for example, there is a file - 1.txt, only root has write permission:
$ll 1.txt
-rw-r--r--. 1 root root 57 Jul 1 12:19 1.txt
For an ordinary user to modify the file, I did the following:
$ sudo chmod u+s /usr/bin/echo
$ ll /usr/bin/echo
-rwsr-xr-x. 1 root root 33128 Oct 31 2018 /usr/bin/echo
However, when the user ran below command, it still got permission error.
$ echo 111 > 1.txt
bash: 1.txt: Permission denied
Then I did a similar test on ls command:
Only root has write permission to test/ directory:
$ ll -d test/
drw-------. 2 root root 34 Jul 1 14:18 test/
a user that run ls command would report an error
$ ls test/
ls: cannot open directory test/: Permission denied
Then setuid on ls command:
$ sudo chmod u+s /usr/bin/ls
$ ll /usr/bin/ls
-rwsr-xr-x. 1 root root 117680 Oct 31 2018 /usr/bin/ls
after this, the user was able to run the command
$ ls test/
1 23 4
What's the difference between echo and ls? Or what I missed here?

`ls -l` for all parent directories

I want to get a list of all directory permissions from current folder to /. For example, for the directory: /var/lib/program/subfolder, I want an output such as:
$ pwd
/var/lib/program/subfolder
$ magic_ls_-l_command somefile
drwxr-xr-x 10 root root 4096 May 15 20:20 var
drwxr-xr-x 10 root root 4096 May 15 20:20 lib
drwxrwxr-x 10 root user 4096 May 16 20:21 program
drwxrwxr-x 10 root user 4096 May 16 20:21 subfolder
-rwxrwxr-- 1 root user 4096 May 16 20:22 somefile
I don't care about the order (from /var to /subfolder or the other way around), the number of hard links or even the date. I just wrote them down to emulate the ls -l output. Also, I don't care how each filename in printed (/var and /lib, var and lib, or /var and /var/lib). I'm just interested in the ownership of each file/directory in the path from the choosen file or pwd to /.
In case I should install some program, I'm under Ubuntu 20.04.
This question has already been answered in superuser.com (I don't know if I can mark a question from one site as duplicate from another). The solution is as simple as writing (assuming I am in the same directory as the target filename):
$ namei -l $(pwd)/somefile ## or `namei -l $(realpath -s somefile)`
Because of -l, it lists basic permissions in long format for each parent directory.
I have to use pwd/realpath because namei doesn't resolve relative paths. If I'm not in the target directory, just write the full path.
I made this small script that does this. I use cd "$1"; pwd to get the current directory so that paths are not canonicalized (say, if you try magic-ls . and your current directory is /var/lib/postgres, but that is a symlink to /mnt/postgres, you will get /var, /var/lib and /var/lib/postgres, while using realpath you would get /mnt and /mnt/postgres)
magic-ls() {
local current=$(cd "$1"; pwd)
while [[ $current != '/' ]]; do
ls -ld "$current"
current=$(dirname "$current")
done
}
Here's an example output:
[leodag#desk ~]$ magic-ls
drwx------ 1 leodag leodag 2722 jun 21 13:49 /home/leodag
drwxr-xr-x 1 root root 18 mai 2 2019 /home
By the way it will also work with no argument since cd "" does not change your directory.
Edit: removed realpath from the while check, since that could lead to unexpected results if there was a link to / in the path, and was unneeded.
I wrote a bash script for you. It'll have some bugs, if you have space in names. If it bothers you, I'm happy for changes recommendations in the comments.
#!/bin/bash
if [ ! -z "$1" ] && [ -e "$1" ]
then
path=`realpath -s "$1"` # read argument as absolute path
else
path="$PWD" # No valid argument, so we take pwd
fi
paths=""
while [ "$path" != / ];do
paths+=" $path"
path=`dirname "$path"`
done
paths+=" $path" # Adding / to pathlist too
ls -ld $paths
With realpath -s you can catch the absolute path, but you wont follow the link. If no argument is given, we will use pwd as the file/directory to list.
We append each path to a list. This gives us the advantage of a better layout in the end, so that we get a nice table because we run ls only once.
Output:
bobafit:~$ magic_ls_-l_command /usr/bin/python3
drwxr-xr-x 21 root root 4096 Jun 20 10:07 /
drwxr-xr-x 14 root root 4096 Sep 5 2019 /usr
drwxr-xr-x 2 root root 110592 Jun 20 10:07 /usr/bin
lrwxrwxrwx 1 root root 9 Apr 7 12:43 /usr/bin/python3 -> python3.8
Just using parameter expansion:
#!/usr/bin/env bash
path="$1"
while test -n "$path"; do
ls -lLd "$path"
path="${path%/*}"
done
calling method :
bash test.sh /var/lib/program/subfolder/somefile
giving
-rw-r--r-- 1 root root 0 Jun 21 18:49 /var/lib/program/subfolder/somefile
drwxr-xr-x 1 root root 4096 Jun 21 18:49 /var/lib/program/subfolder
drwxr-xr-x 1 root root 4096 Jun 21 18:49 /var/lib/program
drwxr-xr-x 1 root root 4096 Jun 21 18:49 /var/lib
drwxr-xr-x 1 root root 4096 Jun 13 19:24 /var
#! /bin/bash
cur=""
IFS="/"
path=`pwd`
for dir in ${path:1}
do
cur=$cur/$dir
ls -lhd "$cur"
done
cur=$cur/$1
ls -lhd "$cur"
Terminal Session:
$ pwd
/tmp/dir_underscore/dir space/dir special #!)
$ ls
bash.sh test.txt
$ ./bash.sh test.txt
drwxrwxrwt 28 root root 36K Jun 21 22:45 /tmp
drwxr-xr-x 3 root root 4.0K Jun 21 22:27 /tmp/dir_underscore
drwxr-xr-x 3 root root 4.0K Jun 21 22:28 '/tmp/dir_underscore/dir space'
drwxr-xr-x 2 root root 4.0K Jun 21 22:54 '/tmp/dir_underscore/dir space/dir special #!)'
-rw-r--r-- 1 root root 0 Jun 21 22:29 '/tmp/dir_underscore/dir space/dir special #!)/test.txt'
This should possibly work:
pwd ; ls -lh ; while true ; do cd .. ; pwd ; ls -lh ; [[ "$PWD" == "/" ]] && break ; done
EDIT: I misunderstood the question at first. Try this:
(pwd ; ls -ldh ; while true ; do cd .. ; pwd ; ls -ldh ; [[ "$PWD" == "/" ]] &&
break ; done ; cd "$START")
EDIT2: fillipe's answer is probably the best, but here's my third and last attempt, which works on both files and directories:
magic_ls() {
fname="$1"
while true ; do
ls -lhd "$fname"
[[ "$fname" == "/" ]] && break ;
fname=$(dirname $(readlink -f "$fname"))
done
}
Just my 2 cents. My mac doesn't have the namei command (perhaps homebrew has a copy), but wanted to whip up a quick version that aligned the output in top-down order
#!/usr/bin/env bash
path="${1%/}"
DIRS=()
while test -n "$path"; do
DIRS=( "$path" "${DIRS[#]}" )
path="${path%/*}"
done
ls -ld "${DIRS[#]}"
Example output:
$ lspath $TMPDIR
lrwxr-xr-x# 1 root wheel 11 Oct 5 2018 /var -> private/var
drwxr-xr-x 7 root wheel 224 Jul 16 2020 /var/folders
drwxr-xr-x# 3 root wheel 96 Apr 5 2018 /var/folders/0c
drwxr-xr-x# 5 me staff 160 Apr 5 2018 /var/folders/0c/2_s_qxd11m3d1smzqdrs3qg40000gp
drwx------# 255 me staff 8160 Oct 7 09:18 /var/folders/0c/2_s_qxd11m3d1smzqdrs3qg40000gp/T

Why count differs between ls and ls -l linux command?

I had a directory with number of files and need to check the count of files present in it.
I tried the following two commands:
ls | wc -l
ls -l | wc -l
and found there are differences while using both commands. (ie. number of files is greater in the usage of second command while comparing to the first command.)
I would like to know the changes happening in the both commands.
From man ls:
-l (The lowercase letter ``ell''.) List in long format. (See below.) If the output is to a terminal, a total sum for all the file sizes is output on a line before the
long listing.
So ls -l adds a header line stating the "total" size of files:
$ ls -l /
total 65
-r--r--r-- 1 root wheel 6197 May 11 21:57 COPYRIGHT
drwxr-xr-x 2 root wheel 1024 Jun 1 16:02 bin
drwxr-xr-x 9 root wheel 1536 Jun 1 16:02 boot
dr-xr-xr-x 8 root wheel 512 Jul 7 20:16 dev
.......

realpath on Cygwin is not same as PWD

$ pwd
/home/Thomas/Utveckling/Cgreen/thoni56/cgreen
$ realpath .
/cygdrive/c/Users/Thomas/Utveckling/Cgreen/thoni56/cgreen
$ cygpath -a .
/cygdrive/c/Users/Thomas/Utveckling/Cgreen/thoni56/cgreen/
Why is this? Why is absolute path from the root /cygdrive and not /?
How do I get an absolute path that starts with /home from a relative path, such as .., if I'm in that tree?
It is the effect of the presence of a link in the path.
Eg:
ls -ld /pub /tmp
lrwxrwxrwx 1 marco Administrators 19 Jun 26 2014 /pub -> /cygdrive/e/cyg_pub
drwxrwxrwx+ 1 marco Administrators 0 May 2 17:49 /tmp
$ realpath /pub /tmp
/cygdrive/e/cyg_pub
/tmp

Symbolic link between two symbolic links

It is possible to make a symbolic link between two symbolic link ?
like this:
root # ls -al /usr/sbin/ash
lrwxrwxrwx 1 root root 17 Mar 23 20:59 /usr/sbin/ash -> /usr/sbin/busybox
root # ls -l /bin/sh
lrwxrwxrwx 1 root root 13 Mar 23 21:00 /bin/sh -> /usr/sbin/ash
Yes, it's possible. You can create them like that:
ln -s /usr/sbin/busybox /usr/sbin/ash
ln -s /usr/sbin/ash /bin/sh

Resources