Make who in all jails - bash

Looking for a script what will show all logged users sorted by FreeBSD jails where they're logged in. So, need run the who command in all currently running FreeBSD jails and in the main host too.
I make this:
who #main host
jls | grep -v JID | while read jid ip host path
do
echo $jid $host
jexec $jid who
done
but the jexec need root execution and i'm logging in usually as non-root and make su everytime is painfull...
Is here any other simple way?

The who command in FreeBSD knows a file argument from where read informations about the logged-in users, the default is /var/run/utx.active - and the file is usually world-readable...
Probably will be enough the next script:
#!/usr/local/bin/bash
while read jpath
do
echo JWHO: ${jpath:-$(hostname)}
who "${jpath}/var/run/utx.active"
done < <( jls -h path | sed '1s:.*::' )
example output:
JWHO: marvin.example.com
smith pts/0 7 nov 20:55 (adsl2343-some-another.example.com)
JWHO: /jails/jail1
JWHO: /jails/testjail
root pts/2 7 nov 20:55 (someother.example.com)
JWHO: /jails/dbjail
steps:
show the path to "root filesystem" for all running jails
run the who for the /var/run/utx.active for the given jail
skip the header line from the jls, - so the 1st output will be the host.
Maybe someone know much simpler solution, e.g. by sorting the ps output or something like...
Comments: you usually don't want to use constructions like command | while read - the pipe forks new shell and you losing values of the variables set inside of the loop, the done < <( commands ) is usually better...

You can enable sudo in your system change your script just a little to:
sudo jexec $jid who
Then your srcipt can run as normal user.

Related

Is it possible to create a file that when read, it runs a command to generate output?

I'd like to create a file, for example lets call it /tmp/not_running_pods, that when read cat /tmp/not_running_pods runs kubectl get pods -o wide | grep -v Running and gives the output to the reading process.
This use case is simplified for example's sake. Not really looking for alternatives, unless it fits this exact case: file that outputs without having a 'service' always running listening for readers
Having a hard time finding anything specific for this on searching. My local env is macos, but hoping for something generalizable to linux/bash/zsh
edit: finally found what was on the tip of my brain, something like inetd / super-server - still looking to see if this would work for this case
when read cat /tmp/not_running_pods runs
A file is static. It exists.
HTTP web servers runs a php script (and much more stuff) to generate the web page for you to view. An SSHD server runs a shell for you to connect with. MYSQL server serves a specific protocol that allows to execute queries. To "do something" when a connection is made typically sockets - network, tcp, but also file sockets - are used, that allow with accept() detect incoming connections and run actually an action on such event.
# in one terminal
$ f() { echo new >&2; echo Hello world; LC_ALL=C date; }; export -f f; socat UNIX-LISTEN:/tmp/file,fork SYSTEM:'bash -c f'
new
new
# in the second terminal
$ socat UNIX-CONNECT:/tmp/file -
Hello world
Tue Jul 19 21:29:03 CEST 2022
$ socat UNIX-CONNECT:/tmp/file -
Hello world
Tue Jul 19 21:29:19 CEST 2022
If you really want to "execute an action when reading from a file", then you have to create your own file system that does that. Primary examples are files in /proc /sys. For user space file systems, write a program using FUSE.
Instead of
$ cat /tmp/not_running_pods
just make ~/bin/not_running_pods:
#! /bin/bash
kubectl get pods -o wide | grep -v Running
with chmod 755 and do
$ not_running_pods
Easy, well-understood, well-supported.

How can i redirect unwanted output on bash login over ssh?

I've got a script, that will use ssh to login to another machine and run a script there. My local script will redirect all the output to a file. It works fine in most cases, but on certain remote machines, i am capturing output that i don't want, and it looks like it's coming from stderr. Maybe because of the way bash is processing entries in its start-up files, but this is just speculation.
Here is an example of some unwanted lines that end up in my file.
which: no node in (/usr/local/bin:/bin:/usr/bin)
stty: standard input: Invalid argument
My current method is to just strip the predictable output that i don't want, but it feels like bad practice.
How can i capture output from only my script?
Here's the line that runs the remote script.
ssh -p 22 -tq user#centos-server "/path/to/script.sh" > capture
The ssh uses authorized_keys.
Edit: In the meantime, i'm going to work on directing the output from my script on machine B to a file and then copying it to A via scp and deleting it on B. But i would really like to be able to suppress the output completely, because when i run the script on machine A, it makes the output difficult to read.
To build on your comment on Raman's answer. Have you tried supressing .bashrc and .bash_profile as shown below?
ssh -p 22 -tq user#centos-server "bash --norc --noprofile /path/to/script.sh" > capture
If rc-files is the problem on some servers you should try and fix the broken rc-files instead of your script/invocation since it'll affect all (non-interactive) logins.
Try running ssh user#host 'grep -ls "which node" .*' on all your servers to find if they have "which node" in any dotfiles as indicated by your error message.
Another thing to look out for is your shebang. You tag this as bash and write CentOS but on a Debian/Ubuntu server #!/bin/sh gives you dash instead of (sh-compatible) bash.
YOu can redirect stdout (2) to /dev/null and redirect the rest to the log fole as follows:
ssh -p 22 -tq user#centos-server bash -c "/path/to/script.sh" 2>/dev/null >> capture

How can I run a command in a separate terminal using sudo without further user interaction

I am trying to automate the running of several tasks, but I need to run them as sudo.
I want to run them in separate terminals so I can watch the output of each.
Here is a sort of minimal example I have setup (because what I am trying to do is more complicated)
Setup two files - note that data is readable as root only and contains 3 lines of example text:
-rw------- 1 root root 33 Nov 15 09:29 data
-rwxrwxrwx 1 root root 11 Nov 15 09:30 test.sh*
test.sh looks like:
#!/bin/bash
cat data
read -p "Press enter to continue"
Also I have user level variable called "SESSION_MANAGER" that is setup in the bash startup... which seems to cause some issues (see later example)
So now I want to spawn various terminals running this script. I tried the following:
Attempt 1
xfce4-terminal -e './test.sh'
output:
cat: data: Permission denied
Press enter to continue
Attempt 2 - using sudo at the start
~/src/sandbox$ sudo xfce4-terminal -e './test.sh'
Failed to connect to session manager: Failed to connect to the session manager: SESSION_MANAGER environment variable not defined
(xfce4-terminal:6755): IBUS-WARNING **: The owner of /home/openbts/.config/ibus/bus is not root!
output:
this is some data
more data
end
Press enter to continue
here you can see that the output of the data file is print ok, but I had some issue with the session manager variable.
Attempt 3 - using sudo in the command
~/src/sandbox$ xfce4-terminal -e 'sudo ./test.sh'
output:
[sudo] password for openbts:
this is some data
more data
end
Press enter to continue
here you can see that everything was well... but I had to enter my password again, which somewhat kills my automation :(
Attempt 4 - start as root
~/src/sandbox$ sudo su
root#openbts:/home/openbts/src/sandbox# xfce4-terminal -e './test.sh'
Failed to connect to session manager: Failed to connect to the session manager: SESSION_MANAGER environment variable not defined
output:
this is some data
more data
end
Press enter to continue
Here, again the output looks good, but I have this SESSION_MANAGER issue... Also the new xfce4-terminal comes out with messed up font/look - I guess this is the root users settings.
Questions
How can I run multiple instances of test.sh each in a new terminal and not have to enter passwords (or interact at all). I can enter the password once at the start of the process (in the original terminal)?
As you can see I got this sort-of working when going in a sudo su, but this issues here are the SESSION_MANAGER variable - not sure if that is an issue, but its very messy looking, but also the xcfe4-terminal looks bad (I guess I can change the root settings to the same as my user settings). So how can I avoid the SESSION_MANAGER issue when running as root?
If you change user-id before you launch your separate terminal, you will see the session-manager issue. So the solution is to run the sudo in the terminal.
You do not want to type passwords in the sudo. You can do that by adding
yourname ALL=(ALL) NOPASSWD: ALL
to /etc/sudoers (at least on slackware). You could also try to set the permissions on the files correct so you would not need root all the time.
Note that adding that line has security implications; you might want to allow just cat without password (in your example), or make even more elaborate rules for sudo. The line I gave is just an example. Personally, I would look at file-permissions.

How do I get the current user's username in Bash?

How do I get the current user's username in Bash? Do I use whoami?
On the command line, enter
whoami
or
echo "$USER"
An alternative to whoami is id -u -n.
id -u will return the user id (e.g. 0 for root).
Use the standard Unix/Linux/BSD/MacOS command logname to retrieve the logged in user. This ignores the environment as well as sudo, as these are unreliable reporters. It will always print the logged in user's name and then exit. This command has been around since about 1981.
My-Mac:~ devin$ logname
devin
My-Mac:~ devin$ sudo logname
Password:
devin
My-Mac:~ devin$ sudo su -
My-Mac:~ root# logname
devin
My-Mac:~ root# echo $USER
root
A hack the I've used on Solaris 9 and Linux and which works fine for both of them:
ps -o user= -p $$ | awk '{print $1}'
This snippet prints the name of the user with the current EUID.
NOTE: you need Bash as the interpreter here.
On Solaris you have problems with methods, described above:
id does not accept the -u and -n parameters (so you will have to parse the output)
whoami does not exist (by default)
who am I prints owner of current terminal (ignores EUID)
$USER variable is set correctly only after reading profile files (for example, /etc/profile)
Two commands:
id prints the user id along with the groups.
Format: uid=usernumber(username) ...
whoami gives the current user name
When root (sudo) permissions are required, which is usually 90%+ when using scripts, the methods in previous answers always give you root as the answer.
To get the current "logged in" user is just as simple, but it requires accessing different variables: $SUDO_UID and $SUDO_USER.
They can be echoed:
echo $SUDO_UID
echo $SUDO_USER
Or assigned, for example:
myuid=$SUDO_UID
myuname=$SUDO_USER
In Solaris OS I used this command:
$ who am i # Remember to use it with space.
On Linux- Someone already answered this in comments.
$ whoami # Without space
REALUSER="${SUDO_USER:-${USER}}"
...gets you the regular user (if non-sudo) → or ← the regular user behind the current sudo call.
The current user's username can be gotten in pure Bash with the ${parameter#operator} parameter expansion (introduced in Bash 4.4):
$ : \\u
$ printf '%s\n' "${_#P}"
The : built-in (synonym of true) is used instead of a temporary variable by setting the last argument, which is stored in $_. We then expand it (\u) as if it were a prompt string with the P operator.
This is better than using $USER, as $USER is just a regular environmental variable; it can be modified, unset, etc. Even if it isn't intentionally tampered with, a common case where it's still incorrect is when the user is switched without starting a login shell (su's default).
For Bash, KornShell (ksh), sh, etc. Many of your questions are quickly answered by either:
man [function]
to get the documentation for the system you are using or usually more conveniently:
google "man function"
This may give different results for some things where Linux and Unix have modest differences.
For this question, just enter "whoami" in your shell.
To script it:
myvar=$(whoami)
On most Linux systems, simply typing whoami on the command line provides the user ID.
However, on Solaris, you may have to determine the user ID, by determining the UID of the user logged-in through the command below.
echo $UID
Once the UID is known, find the user by matching the UID against the /etc/passwd file.
cat /etc/passwd | cut -d":" -f1,3
This is a small simple example bash script I made for pushing my code to my personal gitlab, it spits out my current username in my commit message.
# !/bin/sh
# This example script is for pushing my code to gitlab
echo Starting Push for user : $(whoami), Please enter Commit Message
below:
read varMessage
# this prompts the user for an input messsage , then saves the result in
# a variable
git add .
git commit -m "$(whoami): $varMessage"
git push -u "url_of_project" master
Resultant commit message in my personal gitlab looks like this:-
walexia : updated Matplotib example
All,
From what I'm seeing here all answers are wrong, especially if you entered the sudo mode, with all returning 'root' instead of the logged in user. The answer is in using 'who' and finding eh 'tty1' user and extracting that. Thw "w" command works the same and var=$SUDO_USER gets the real logged in user.
Cheers!
TBNK
Get the current task's user_struct
#define get_current_user() \
({ \
struct user_struct *__u; \
const struct cred *__cred; \
__cred = current_cred(); \
__u = get_uid(__cred->user); \
__u; \
})

Running script with admin permissions on OS X

I've tried my best to find out a solution with the many script questions on Stack Overflow and the internet, but I can't seem to find the solution I need.
What I want to do is create a more automated and less clicking solution to remove all the Mobile cached user accounts on a system. I've been logging in and manually going to user accounts and removing the users one at a time by clicking the "-" button, then clicking "Delete Immediately" for the user data. This works, but is time consuming and I have better things to do with my time. So I knew there had to be a way to do this with a script.
I ran across this code:
for cuser in `dscl . -list /Users AuthenticationAuthority | grep LocalCachedUser | awk '{print $1}' | tr '/n' ' '`; do
dscl . -delete /Users/$cuser
done
If I run this in terminal I get permission errors. So I figured I need to run it with sudo. So I started looking into creating AppleScripts to run the script, but I can't seem to find the right way to do it.
Any ideas? By the way, I'm new to scripting on the Mac, so please comment your code so I know whats happening, and so I don't just run some script code without know what it'll do. :)
Thanks
To perform a shell script with sudo or administrator privileges append with administrator privileges to the end of your do shell script line. For example:
do shell script "/path/to/script/file.sh" user name "adminusershortname" password "password" with administrator privileges
You can find more on Apple's technote dealing with do shell script
That said, saving this as a shell script and running the shell script using sudo would work just as well.
#! /bin/sh
for cuser in `/usr/bin/dscl . -list /Users AuthenticationAuthority | grep LocalCachedUser | awk '{print $1}' | tr '/n' ' '`; do
/usr/bin/dscl . -delete /Users/$cuser
done
Save it as say removeUser.sh, use chmod to set it as executable (chmod 755) and then run it (sudo ./removeUser.sh)
You can do this by editing your system's sudoers file. This will allow the account you use to run this script (via cron, etc.) the ability to run sudo without a password.
To edit the sudoers file you use visudo, but it must be run with admin permission. Try:
$ sudo visudo
Add a line like the following to the end of the file, replacing user_name with the user who will run your script. Note, use tabs between each field.
user_name ALL=(ALL) NOPASSWD:ALL
Now user_name should be able to type sudo and will not be prompted for a password.
Also note that visudo is a text editor that mirrors the vi editor and uses the same commands as vi.
I don't have a mac handy so I can't verify if this would work.
Try running
su -
Then running your script. If that works, try
crontab -e
and adding an entry to run that script of yours.
Are you familiar with crontab? well if not google it if need be.
But basically to run it every day at midnight you'd have something like
0 * * * * /path/to/script
See: http://en.wikipedia.org/wiki/Cron

Resources