Archive for the 'bash' Category

26
Aug
14

Finding the process of a listening socket

I had a irc user today asked me how they can find the process id of a listening port.  The obvious answer is to use netstat -lnap; however there are occasions when this will show a dash instead of the process ID.  This occurs when some kernel module spawned the PID that owns the socket.  RPC behaves in this manner and the simplest way to find the pid in that case is to use rpcinfo -p. our as pointed out in the initial irc chat you can use the nmap rpcinfo nse script as follows.

nmap -sU -p 111 --script rpcinfo localhost

however i suggested that is should be possible to find these PID’s by parsing the proc file system. using the netstat -e switch we get the inode of the listening socket and with a bit of hacking i came up with the following test code.

#!/bin/sh
INODE=304
for i in /proc/*/fd/*
do
   SOCKET_INODE=$(stat -c %N ${i} 2>/dev/null | awk -F\: '/socket:\[[0-9]+\]/ {gsub(/[\[\]]/, "", $NF);print $NF}')
   [ "${SOCKET_INODE%?}" == "${INODE}" ] && awk -F\/ '{print $3}'<<< ${i}
done

Unfortunately i don’t have a machine that shows these symptoms and the user disconnected from IRC before i could get them to check. However i think this could be reasonably expanded to the following.

netstat -lnptue | awk '{if ($NF == "-")print $0}' | while read CONNECTION
do
	CONN_TOKENS=($CONNECTION)
	LOCAL_ADDRESS=${CONN_TOKENS[3]}
	INODE=${CONN_TOKENS[7]}
	for i in /proc/*/fd/*
	do
		SOCKET_INODE=$(stat -c  %N ${i} 2>/dev/null | awk -F\: '/socket:\[[0-9]+\]/ {gsub(/[\[\]]/, "", $NF);print $NF}')
		if [ "${SOCKET_INODE%?}"  == "${INODE}"]
		then
			PID=$(awk -F\/ '{print $3}'<<< ${i})
			echo "${LOCAL_ADDRESS}: ${PID}"
		fi
	done
done

This is very inefficient as we scan the whole of proc for every entry we find but i will leave it as an exercise for the reader to optimise. Not sure if this is of any use other then my own curiosity so please feel free to leave feedback.

10
Sep
13

Error Handling in bash

I have never really liked error handling in bash but a few weeks back i came across the ability to use traps. this is an awesome feature and i don’t know why i have never come across it before. So the information i generally want when there is an error is:
* Error code.
* Line number of the error.
* and the command that failed.

The error code is simple we all know $? has the error of the last run command. The line number also pretty easy a quick search of the man page presents us with LINENO. the command of the failed is a bit tricky. we have BASH_COMMAND however this doesn’t give us what we want. consider the following script

#!/bin/bash
trap 'echo ${BASH_COMMAND}' err
TMP=/bla
ls -l ${TMP}

as /bla dose not exit ls will error, the trap will be sprung and the script will print out

ls -l ${TMP}

unfortunately the TMP variable has not been resolved. this is a bit annoying if the offending line is a loop. to fix this a got a bit of help from a colleague and we get something that looks pretty ugly but works

#!/bin/bash
trap 'echo $(eval echo ${BASH_COMMAND})' err
TMP=/bla
ls -l ${TMP}

So my finale header looks like this

#/bin/bash
set -e
trap 'echo "ERROR ($?) line ${LINENO}: $(eval echo ${BASH_COMMAND})' err