tech-pkg archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Samba 3.x: findsmb as Bourne shell (getting rid of Perl)



As I have suggested, in order to get rid of Perl as a run dependency
to Sambe (at least 3.x) here is a rewrite of the Perl findsmb script.

It corrects several bugs:
	- the broadcast address option could not be used (shifting too
	much);
	- name was set to "unknown nis name" and then, if name was set
	(even with this "false" value) a query was sent;
	- there was no help option;
	- debug information was sent to stdout;
	- the output was not correctly aligned to the header.

I'd like others with Samba to test the script before submitting it.

There is one variable to adjust eventually: SAMBABINDIR (it exists in
the Perl script). Default value is "/usr/pkg/bin"

I have added one supplementary variable: HOSTS_FILE that defaults to
"/etc/hosts" for making the equivalent to perl:gethostbyaddr (this
file is not used if getent(1) exists in the PATH).

You can set both SAMBABINDIR and HOSTS_FILE in the environment if the
default are not correct (correct values would be set at compile time).
-- 
        Thierry Laronde <tlaronde +AT+ polynum +dot+ com>
                     http://www.kergis.com/
                       http://www.sbfa.fr/
Key fingerprint = 0FF7 E906 FBAF FE95 FD89  250D 52B1 AE95 6006 F40C
#!/bin/sh
# Rewrite of the SAMBA Perl script findsmb to a POSIX.2 Bourne shell
# compliant one. (Thierry Laronde, 2019-07-21)

set -e

usage="Usage: findsmb [-h] [-d|-D] [-r] [subnet_broadcast_address]
	List machines on the current subnet or the subnet specified.

Options:
	-d|-D	enable Debug
	-h		display this Help message
	-r		-r option passed to nmblookup when finding netbios name

Output:
	Local master browsers are prefixed by a '+'.
	Domain master browsers are prefixed by a '*'.
"

#========== Installation dependent
#
: ${TMPDIR:=/tmp}

: ${SAMBABINDIR:="/usr/pkg/bin"}
: ${HOSTS_FILE:="/etc/hosts"}

#========== NOTHING TO CHANGE BELOW

#========== Subr
#
iplist="$TMPDIR/$$.iplist"
nmblookuplist="$TMPDIR/$$.nmblookuplist"
smbclientlist="$TMPDIR/$$.smbclientlist"

clean_tmp()
{
	rm -f "$iplist" "$nmblookuplist" "$smbclientlist"
}

error()
{
	printf "$@" >&2
	clean_tmp
	exit 1
}

# Does gethostbyaddr. Start by looking local host names in the hosts
# file and query DNS if this fails.
#
# Takes: an ip address;
# Returns: a string, perhaps empty, with the name.
#
getname()
{
	junk=

	# Looking local defined names.
	#
	if type getent >/dev/null 2>&1; then
		junk=$(getent hosts  $1\
			| sed 's/[ 	][ 	]*/ /g'\
			| cut -d ' ' -f 2)
	else
		junk=$(sed -n /^$1[ 	]/'s/[ 	][ 	]*/ /gp' "$HOSTS_FILE"\
			| cut -d ' ' -f 2)
	fi

	if test ! -z "$junk"; then # DONE
		echo $junk
		return
	fi

	# Not found; querying DNS.
	#
	if type nslookup >/dev/null 2>&1; then
		junk=$(nslookup $1 | sed -n 's/^.*name =[ 	]*\([^ 	][^ 	]*\)$/\1/p')
	elif type dig >/dev/null 2>&1; then
		junk=$(dig -x $1 | sed -e '/^;/d' -e '/^$/d'\
			-e 's/^.*[ 	]\([^ 	][^ 	]*\)/\1/'\
			| sed 1q)
	fi

	echo $junk
}

#========== Checking: no stores
#
debug=NO
nmblookup_opt=
broadcast_opt=

while test $# -gt 0; do
	case "$1" in
		-h) echo "$usage"; exit 0;;
		-d|-D) debug=YES;;
		-r) nmbloolup_opt="-r";;
		-*) printf "$0: unknown option '$1'\n"
			error "$usage";;
		*) broadcast_opt="-B $1";;
	esac
	shift
done

#========== Stores

# We start by getting the addresses that will be the first field of
# information published.
#
{ $SAMBABINDIR/nmblookup $broadcast_opt '*' --debuglevel=0\
	|| error "Can't run nmblookup '*'.\n"; } >"$iplist"

# Printing header
#
printf "\n                                *=DMB\n"
printf "                                +=LMB\n"
printf "IP ADDR         NETBIOS NAME     WORKGROUP/OS/VERSION $broadcast_opt\n"
# Note: the "%c" circumvent a bug treating a leading - as option.
#
printf "%c--------------------------------------------------------------------\n" -

# For each address, we will try to fill the remaining informations.
# So a record is 3 fields: ip, name and info.
#
sed -n -e 's/ \*<00>.*$//p' -e 's/[ 	]*//g' "$iplist" | sort -n\
	| while read ip; do

	# Trying to define the second field: the name.
	#
	# Start by querying via netbios.
	#
	{ $SAMBABINDIR/nmblookup $nmbloolup_opt -A $ip --debuglevel=0\
		|| error "Can't get nmb name list.\n"; } >"$nmblookuplist"

	record=$(sed -n '/<00>/{p; q;}' "$nmblookuplist")

	if test ! -z "$record"; then # got a record from netbios
		is_groupname=$(echo $record | sed -n '/GROUP/p')
		if test ! -z "$is_groupname"; then
			name=$(getname $ip)
		else
			name=$(echo $record\
				| sed 's/^[ 	]*\([^ 	].*[^ 	]\)[ 	][ 	]*<00>.*$/\1/')
		fi

		# do an smbclient command on the netbios name if set.
		#
		if ! test -z "$name"; then
			{ $SAMBABINDIR/smbclient -L $name -I $ip -N --debuglevel=1 2>&1\
				|| error "Can't do smbclient command.\n"; } >"$smbclientlist"

			if test $debug = YES; then
				printf "\n======================== DEBUG:  BEGIN ========================\n" >&2
				printf "=================== DEBUG: nmblookup output ===================\n" >&2
				cat "$nmblookuplist" >&2
				printf "=================== DEBUG: smbclient output ===================\n" >&2
				cat "$smbclientlist" >&2
				printf "========================= DEBUG:  END =========================\n\n" >&2
			fi

			# We will try to set the third field: informations.
			#
			info=$(sed -n '/OS=/{p; q;}' "$smbclientlist")
			if test ! -z "$info"; then
				# Strip out descriptions to make line shorter.
				#
				info=$(echo $info | sed -e 's/Domain=//'\
					-e 's/OS=//' -e 's/Server=//')

			else # no OS= string in response (WIN95 client)
				# for WIN95 clients get workgroup name from nmblookup response
				#
				record=$(sed -n '/<00> - <GROUP>/{p; q;}' "$nmblookuplist")
				if test ! -z "$record"; then
					info=$(echo $record\
						| sed 's/^[ 	]*\([^ 	].*[^ 	]\)[ 	][ 	]*<00>.*$/\1/')
					info="[$info]"
				else
					info="Unknown Workgroup"
				fi

			fi
		else
			name="unknown nis name";
		fi

		# see if machine registered a local master browser name
		if grep -q '<1d>' "$nmblookuplist"; then
			master='+'			# indicate local master browser
			if grep -q '<1b>' "$nmblookuplist"; then	# how about domain master browser?
				master='*'			# indicate domain master browser
			fi
		else
			master=' '			# not a browse master
		fi

		info="$master$info"

	else # didn't get a record by netbios
		name=$(getname $ip)
		test ! -z "$name" || name="unknown nis name";
		info=""
		if test $debug = YES; then
			printf "\n======================== DEBUG:  BEGIN ========================\n" >&2
			printf "=================== DEBUG: nmblookup output ===================\n" >&2
			cat "$nmblookuplist" >&2
			printf "========================= DEBUG:  END =========================\n\n" >&2
		fi
	fi

	# Publish the 3 fields.
	#
	printf "%-16s%-16s%s\n" "$ip" "$name" "$info"
done

clean_tmp

exit 0


Home | Main Index | Thread Index | Old Index