A script to test for traffic from a streaming server? - linux

I have an instrument that streams data out a tcp port, and I'd like to use standard tools in a script to determine if the stream is available.
Manually I use ncat, which promptly exits if the data stream isn't available.
Here's my initial bash script:
#!/bin/bash
ncat somehost 1234 >/dev/null &
pid=$!
sleep 1
if [ -d /proc/$pid/ ]; then
kill -KILL $pid
echo "It's alive, ALIVE\!"
# Launch clients
else
echo "He's dead, Jim."
# Perform resurrection
fi
It works, but I'm wondering if there is a simpler or better way to accomplish this that doesn't rely on job control or procfs or even ncat. I'd also like to know how much data was sent before a timeout exires.
And, yes, in bash ncat host port can be replaced by cat </dev/tcp/host/port, but I'd also like to avoid bash-isms (so it can work under busybox).
Another approach would be to use wc to count the lines/chars output by ncat, since it outputs only one line and exits if the connection can't be made. But I can't wait forever for termination if the stream is up, so I'd need to use something like timeout, which has its own complications when trying to access the output of a command.
Is there a "plain" approach that works with minimal dependencies?
Or should I write a simple tool instead? It would return the number of bytes read if a connection was made to host/port, a negative errno otherwise, and would support a wait time and protocol spec (tcp/udp). A return value of 0 would mean the connection was made, but no data arrived before the wait time expired (a good thing to know).
Or maybe patch ncat to do the above?

I use netcat in FreeBSD, which has a -z option that simply checks whether a port is open. This eliminates the background and sleep you're using in your script.
-z Specifies that nc should just scan for listening daemons, without
sending any data to them.
The option exists in netcat on an old Ubuntu box here, so that might be an option for you.
$ nc -z somehost 1234 && echo "It's alive, ALIVE!"
I don't see an equivalent option in ncat. You may be able to compile netcat into busybox; it's much smaller than ncat, at least on my systems:
Linux:
$ ls -lH `which nc ncat`
-rwxr-xr-x 1 root root 31296 2010-02-21 01:32 /bin/nc
-rwxr-xr-x 1 root root 130448 2009-11-06 04:39 /usr/bin/ncat
FreeBSD:
ls -l `which nc ncat`
-r-xr-xr-x 1 root wheel 28112 Jan 15 14:53 /usr/bin/nc
-rwxr-xr-x 1 root wheel 182775 Mar 19 2012 /usr/local/bin/ncat
Of course, this doesn't help you check the amount of traffic that has come through the stream, or to analyse its content. For that, I think your solution is innovative and reasonable, though the challenge you've presented may not be resolvable easily.
You can use ps to avoid the procfs dependency, and you can store things in a temp file for analysis rather. Note that busybox should include a mktemp, but you should probably check the options. I haven't tested this:
#!/bin/sh
TMPFILE=`mktemp /tmp/str.XXXX`
trap "rm -f $TMPFILE" 0 1 2 3 15
nc somehost 1234 > $TMPFILE &
pid=$!
sleep 1
if ps $pid >/dev/null; then
kill -KILL $pid
echo -n "It's alive, "
if [ -s $TMPFILE ]; then
echo "ALIVE!"
else
echo "but unresponsive."
fi
else
echo "He's dead, Jim."
fi
That's all I've got. And it's not much different from what you already have.
Another option might be to build a custom tool that you might be able to compile into your own busybox, but that'll be a c question rather than a shell question. :-)

Related

Taking sequentially output of multi ssh with bash scripting

I'm wrote a bash script and I don't have a chance to download pssh. However, I need to run multiple ssh commands in parallel. There is no problem so far, but when I run ssh commands, I want to see the outputs sequentially from the remote machine. I mean one ssh has multiple outputs and they get mixed up because more than one ssh is running.
#!/bin/bash
pid_list=""
while read -r list
do
ssh user#$list 'commands'&
c_pid=$!
pid_list="$pid_list $c_pid"
done < list.txt
for pid in $pid_list
do
wait $pid
done
What should I add to the code to take the output unmixed?
The most obvious way to me would be to write the outputs in a file and cat the files at the end:
#!/bin/bash
me=$$
pid_list=""
while read -r list
do
ssh user#$list 'hostname; sleep $((RANDOM%5)); hostname ; sleep $((RANDOM%5))' > /tmp/log-${me}-$list &
c_pid=$!
pid_list="$pid_list $c_pid"
done < list.txt
for pid in $pid_list
do
wait $pid
done
cat /tmp/log-${me}-*
rm /tmp/log-${me}-* 2> /dev/null
I didn't handle stderr because that wasn't in your question. Nor did I address the order of output because that isn't specified either. Nor is whether the output should appear as each host finishes. If you want those aspects covered, please improve your question.

Why doesn't tcpdump run in background?

I logged in a virtual machine via ssh and I tried to run a script in background, the script is shown below:
#!/bin/bash
APP_NAME=`basename $0`
CFG_FILE=$1
. $CFG_FILE #just some variables
CMD=$2
PID_FILE="$PIDS_DIR/$APP_NAME.pid"
CUR_LOG_DIR=$LOGS_RUNNING
echo $$ > $PID_FILE
#Main script code
#This script shall be called using the following syntax
# $ nohup script_name output_dir &
TIMESTAMP=`date +"%Y%m%d%H%M%S"`
CAP_INTERFACE="eth0"
/usr/sbin/tcpdump -nei $CAP_INTERFACE -s 65535 -w file_result
rm $PID_FILE
The result should be tcpdump running in background, redirecting the command result to file_result.
The script is called with:
nohup $SCRIPT_NAME $CFG_FILE start &
And It is stopped calling the STOP_SCRIPT:
##STOP_SCRIPT
PID_FILE="$PIDS_DIR/$APP_NAME.pid"
if [ -f $PID_FILE ]
then
PID=`cat $PID_FILE`
# send SIGTERM to kill all children of $PID
pkill -TERM -P $PID
fi
When I check the file_result, after running the stop script, It is empty.
What is happening? How can I solve it?
I found this link: https://it.toolbox.com/question/launching-tcpdump-processes-in-background-using-ssh-060614
The author seems to have faced a similar issue. They debate about race conditions, but I didn't understand completely.
I'm not sure what you're trying to accomplish by having the startup script itself continue to run, but here's an approach that I think accomplishes what you're trying to do, namely start tcpdump and have it continue to run immune to hangups via nohup. I've simplified things a bit for illustrative purposes - feel free to add any variables back as you see fit, such as the nohup.out output directory, TIMESTAMP, etc.
Script #1: tcpdump_start.sh
#!/bin/sh
rm -f nohup.out
nohup /usr/sbin/tcpdump -ni eth0 -s 65535 -w file_result.pcap &
# Write tcpdump's PID to a file
echo $! > /var/run/tcpdump.pid
Script #2: tcpdump_stop.sh
#!/bin/sh
if [ -f /var/run/tcpdump.pid ]
then
kill `cat /var/run/tcpdump.pid`
echo tcpdump `cat /var/run/tcpdump.pid` killed.
rm -f /var/run/tcpdump.pid
else
echo tcpdump not running.
fi
To start tcpdump, just run tcpdump_start.sh.
To stop the tcpdump instance started with tcpdump_start.sh, just run tcpdump_stop.sh.
The captured packets will be written to the file_result.pcap file, and yes, it's a pcap file, not a text file, so it helps to name it with the proper file extension. The tcpdump statistics will be written to the nohup.out file when tcpdump is terminated.
I too had faced problems when running tcpdump over an SSH session.
In my case, I was running
sudo nohup tcpdump -w {pcap_dump_file} {filter} > /dev/null 2>&1 &
Where, running this command over Paramiko SSH session as a background process was the problem.
To get around this, I used screen utility of Linux.
screen is an easy to use tool for long-running of processes as a service.
Might be an old post, but this is also relevant. I couldn;t understand why no file was being created only to realise that the file might not be created until a certain amount of data had been captured.
https://github.com/the-tcpdump-group/tcpdump/issues/485

How to check if file size is not incrementing ,if not then kill the $$ of script

I am trying to figure out a way to monitor the files I am dumping from my script. If there is no increment seen in child files then kill my script.
I am doing this to free up the resources when not needed. Here is what I think of , but I think my apporch is going to add burden to CPU. Can anyone please suggest more efficent way of doing this?
Below script is suppose to poll in every 15 sec and collect two file size of same file, if the size of the two samples are same then exit.
checkUsage() {
while true; do
sleep 15
fileSize=$(stat -c%s $1)
sleep 10;
fileSizeNew=$(stat -c%s $1)
if [ "$fileSize" == "$fileSizeNew" ]; then
echo -e "[Error]: No activity noted on this window from 5 sec. Exiting..."
kill -9 $$
fi
done
}
And I am planning to call it as follow (in background):
checkUsage /var/log/messages &
I can also get solution if, someone suggest how to monitor tail command and if nothing printing on tail then exit. NOT SURE WHY PEOPLE ARE CONFUSED. End goal of this question is to ,check if the some file is edited in last 15 seconds. If not exit or throw some error.
I have achived this by above script,but I don't know if this is the smartest way of achiveing this. I have asked this question to know views from other if there is any alternative way or better way of doing it.
I would based the check on file modification time instead of size, so something like this (untested code):
checkUsage() {
while true; do
# Test if file mtime is 'second arg' seconds older than date, default to 10 seconds
if [ $(( $(date +"%s") - $(stat -c%Y /var/log/message) )) -gt ${2-10} ]; then
echo -e "[Error]: No activity noted on this window from ${2-10} sec. Exiting..."
return 1
fi
#Sleep 'first arg' second, 15 seconds by default
sleep ${1-15}
done
}
The idea is to compare the file mtime with current time, if it's greater than second argument seconds, print the message and return.
And then I would call it like this later (or with no args to use defaults):
[ checkusage 20 10 ] || exit 1
Which would exit the script with code 1 as when the function return from it's infinite loop (as long as the file is modified)
Edit: reading me again, the target file could be a parameter too, to allow a better reuse of the function, left as an exercise to the reader.
If on Linux, in a local file system (Ext4, BTRFS, ...) -not a network file system- then you could consider inotify(7) facilities: something could be triggered when some file or directory changes or is accessed.
In particular, you might have some incron job thru incrontab(5) file; maybe it could communicate with some other job ...
PS. I am not sure to understand what you really want to do...
I suppose an external programme is modifying /var/log/messages.
If this is the case, below is my script (with minor changes to yours)
#Bash script to monitor changes to file
#!/bin/bash
checkUsage() # Note that U is in caps
{
while true
do
sleep 15
fileSize=$(stat -c%s $1)
sleep 10;
fileSizeNew=$(stat -c%s $1)
if [ "$fileSize" == "$fileSizeNew" ]
then
echo -e "[Notice : ] no changes noted in $1 : gracefully exiting"
exit # previously this was kill -9 $$
# changing this to exit would end the program gracefully.
# use kill -9 to kill a process which is not under your control.
# kill -9 sends the SIGKILL signal.
fi
done
}
checkUsage $1 # I have added this to your script
#End of the script
Save the script as checkusage and run it like :
./checkusage /var/log/messages &
Edit :
Since you're looking for better solutions I would suggest inotifywait, thanks for the suggestion from the other answerer.
Below would be my code :
while inotifywait -t 10 -q -e modify $1 >/dev/null
do
sleep 15 # as you said the polling would happen in 15 seconds.
done
echo "Script exited gracefully : $1 has not been changed"
Below are the details from the inotifywait manpage
-t <seconds>, --timeout <seconds> Exit if an appropriate event has not occurred within <seconds> seconds. If <seconds> is zero (the default),
wait indefinitely for an event.
-e <event>, --event <event> Listen for specific event(s) only. The events which can be listened for are listed in the EVENTS section.
This option can be specified more than once. If omitted, all events
are listened for.
-q, --quiet If specified once, the program will be less verbose. Specifically, it will not state when it has completed establishing all
inotify watches.
modify(Event) A watched file or a file within a watched directory was
written to.
Notes
You might have to install the inotify-tools first to make use of the inotifywait command. Check the inotify-tools page at Github.

Bash Shell: How can I know if TeamViewer has disconnected?

Sometimes TeamViewer disconnects itself (or gets disconnected) from its internet's main servers.
I am programming a script that will check if connection is lost and, if yes, kills and reopens the concerned process to make TeamViewer up and running again.
The problem is: I don't know how to discover that TeamViewer has lost its remote access capability (this is: the capability to be remotely accessed and controlled).
Tested until now:
Check TeamViewer process and/or daemon. Not valid: they keep working even after disconnected.
NICs review. Not valid: TeamViewer seems not to add any.
See the TeamViewer's main window. Not programmatically valid or easy to implement.
How can I programmatically know if TeamViewer has disconnected?
I don't know if this method differs between platforms, but at least I would like to know about a solution for some Linux shell. Bash if possible.
Probably I'm late, but run into the same problem and found a possible solution. I'm using teamviewer 12.
I noticed that, in my case sometimes some GUI related process are not launched so the machine is not online in my computer and contact list, if I ssh it and check for the list of teamviewer processes using:
ps -ef | grep [t]eamviewer
I get just one process, the teamviewer daemon:
root 1808 1 0 09:22 ? 00:00:53 /opt/teamviewer/tv_bin/teamviewerd -d
But, when everything is fine I have:
root 1808 1 0 09:22 ? 00:00:53 /opt/teamviewer/tv_bin/teamviewerd -d
rocco 10975 8713 0 09:31 ? 00:00:58 /opt/teamviewer/tv_bin/wine/bin/wineserver
rocco 11064 10859 0 09:31 ? 00:00:33 /opt/teamviewer//tv_bin/TVGuiSlave.64 31 1
rocco 11065 10859 0 09:31 ? 00:00:28 /opt/teamviewer//tv_bin/TVGuiDelegate 31 1
So simply counting the number of process works for me..
#!/bin/bash
online() {
## Test connection
ping -c1 www.google.com > /dev/null
return $?
}
online
if (test $? -eq 0)
then
network=$(ps -ef | grep [t]eamviewer | wc -l)
if (test $network -gt 3)
then
echo Machine online, teamviewer connected
else
echo Machine online, teamviewer not connected, trying restart daemon
sudo teamviewer --daemon restart
fi
fi
Have you considered trapping the signal(if possible) and executing a function that will restart TeamViewer.
Start it from a script and trap an exit signal
function restartTV {
# re-start TeamViewrt
sudo /etc/init.d/something start
}
trap finish EXIT # or appropriate signal
sudo /etc/init.d/something stop
# Do the work...

Redirecting Output of Bash Child Scripts

I have a basic script that outputs various status messages. e.g.
~$ ./myscript.sh
0 of 100
1 of 100
2 of 100
...
I wanted to wrap this in a parent script, in order to run a sequence of child-scripts and send an email upon overall completion, e.g. topscript.sh
#!/bin/bash
START=$(date +%s)
/usr/local/bin/myscript.sh
/usr/local/bin/otherscript.sh
/usr/local/bin/anotherscript.sh
RET=$?
END=$(date +%s)
echo -e "Subject:Task Complete\nBegan on $START and finished at $END and exited with status $RET.\n" | sendmail -v group#mydomain.com
I'm running this like:
~$ topscript.sh >/var/log/topscript.log 2>&1
However, when I run tail -f /var/log/topscript.log to inspect the log I see nothing, even though running top shows myscript.sh is currently being executed, and therefore, presumably outputting status messages.
Why isn't the stdout/stderr from the child scripts being captured in the parent's log? How do I fix this?
EDIT: I'm also running these on a remote machine, connected via ssh using pseudo-tty allocation, e.g. ssh -t user#host. Could the pseudo-tty be interfering?
I just tried your the following: I have three files t1.sh, t2.sh, and t3.sh all with the following content:
#!/bin/bash
for((i=0;i<10;i++)) ; do
echo $i of 9
sleep 1
done
And a script called myscript.sh with the following content:
#!/bin/bash
./t1.sh
./t2.sh
./t3.sh
echo "All Done"
When I run ./myscript.sh > topscript.log 2>&1 and then in another terminal run tail -f topscript.log I see the lines being output just fine in the log file.
Perhaps the things being run in your subscripts use a large output buffer? I know when I've run python scripts before, it has a pretty big output buffer so you don't see any output for a while. Do you actually see the entire output in the email that gets sent out at the end of topscript.sh? Is it just that while the processes run you're not seeing the output?
try
unbuffer topscript.sh >/var/log/topscript.log 2>&1
Note that unbuffer is not always available as a std binary in old-style Unix platforms and may require a search and installation for a package to support it.
I hope this helps.

Resources