Mini Shell
#!/usr/bin/sh
# $Id: osql,v 1.12 2011-05-11 03:08:13 jklowden Exp $
#
# Check odbc.ini, odbcinst, and, optionally, freetds.conf,
# then execute isql (assume it's unixODBC's isql).
#
USAGE="Syntax: $(basename "$0") -S server -U user -P password"
while getopts I:S:U:P: OPTION
do
case ${OPTION} in
I) OVER_DIR=${OPTARG} # override
;;
S) DSN=${OPTARG}
;;
U) USERNAME=${OPTARG}
;;
P) PASSWORD=${OPTARG}
;;
\?) echo "$USAGE"
exit 1
;;
esac
done
#cho ${DSN} ${USERNAME} ${PASSWORD}
if [ -z "${DSN}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]
then
echo "$USAGE"
exit 1
fi
ISQL=$(command -v isql)
if [ -z "${ISQL}" ]
then
echo "$(basename "$0"): error: no \"isql\" command found. Is unixODBC installed?"
exit 1
fi
# Establish ODBC prefix directory
ISQL_DIR=$(strings "${ISQL}" | grep ^/ | grep -v elf | grep -v '\.so\.' | head -1 | sed 's/lib$/etc/' )
INI_DIRNAME="/tmp/$(basename "$0").$$"
exec 3> "${INI_DIRNAME}"
# Check the libraries, too.
if [ -z "${OVER_DIR}" ]
then
libcmd='ldd "${ISQL}" | awk "/libodbc\./ {print \$3}"'
if ! command -V ldd >/dev/null 2>&1 && command -V otool >/dev/null 2>&1
then
libcmd='otool -L "${ISQL}" | awk "/libodbc\./ {print \$1}"'
fi
echo "checking shared odbc libraries linked to isql for default directories..."
(echo ${ISQL_DIR}; eval "$libcmd") \
| while read L
do
strings "$L" | grep '^/' | grep -v '/lib' \
| while read D
do
if [ ! -s "${INI_DIRNAME}" ]
then
printf " trying %s ... " "$D"
if [ -d "$D" ] && [ -r "${D}/odbc.ini" ]
then
echo "$D" >&3
printf "OK"
else
printf "no"
fi
printf "\n"
fi
done
done
fi
exec 3>&-
ODBC_DIR=$(cat "${INI_DIRNAME}") && rm "${INI_DIRNAME}"
if [ -z "${ODBC_DIR}" ] && [ -z "${OVER_DIR}" ]
then
echo "$(basename "$0"): problem: no potential directory strings in \"$(command -v isql)\""
echo "$(basename "$0"): advice: use \"osql -I DIR\" where DIR unixODBC\'s install prefix e.g. /usr/local"
echo "isql strings are:"
strings "${ISQL}" | grep ^/ | sed 's/^/+ /'
#xit 1
fi
if [ "${OVER_DIR}" ]
then
if [ -d "${ODBC_DIR}" ]
then
echo "\"${ODBC_DIR}\" is a directory, overridden by"
else
echo "\"${ODBC_DIR}\" is NOT a directory, overridden by"
fi
echo "\"${OVER_DIR}\"."
if [ -d "${OVER_DIR}" ]
then
ODBC_DIR=${OVER_DIR}
else
echo "$(basename "$0"): error: \"${OVER_DIR}\" is not a directory"
exit 1
fi
fi
# Look for server entry in odbc.ini
echo 'checking odbc.ini files'
for F in "${HOME}/.odbc.ini" "${ODBC_DIR}/odbc.ini"
do
if [ ! -d "$(dirname "$F")" ]
then
echo "warning: $(dirname "$F") is not a directory"
continue
fi
if [ -r "$F" ]
then
echo " reading $F"
else
echo " cannot read \"$F\""
continue
fi
grep -F "[${DSN}]" "$F" > /dev/null
if [ $? -eq 0 ]
then
echo "[${DSN}] found in $F"
ODBC_INI=$F
break
else
echo "[${DSN}] not found in $F"
fi
done
if [ -z "${ODBC_INI}" ]
then
echo "$(basename "$0"): error: unable to locate ${DSN} in any odbc.ini"
exit 1
fi
# Report finding of server entry
echo found this section:
SED_CMD="/^\[${DSN}\]/,/^[[:space:]]*$/ { s/^/ /; p; }"
sed -ne "${SED_CMD}" "${ODBC_INI}"
#
# Examine server entry in odbc.ini
#
# Find the driver in the servername or default section
for D in "${DSN}" 'default'
do
echo "looking for driver for DSN [$D] in ${ODBC_INI}"
grep "$D" "${ODBC_INI}" > /dev/null
if [ $? -eq 0 ]
then
CMD="/^\[$D\]/,/^[[:space:]]*$/ { s/^/ /; p; }"
DRIVER_LINE=$(sed -ne "${CMD}" "${ODBC_INI}" \
| grep -Ei '^[[:space:]]*driver[[:space:]]*=')
if [ -z "${DRIVER_LINE}" ]
then
echo " no driver mentioned for [$D] in $(basename "${ODBC_INI}")"
continue
fi
echo " found driver line: \"${DRIVER_LINE}\""
DRIVER=$(echo "${DRIVER_LINE}" \
| awk -F ' *= *' '{print $2}' \
| sed 's/[[:space:]][[:space:]]*//g')
if [ "${DRIVER}" ]
then
echo " driver \"${DRIVER}\" found for [$D] in $(basename "${ODBC_INI}")"
break
else
echo " driver line for [$D] incomplete in $(basename "${ODBC_INI}")"
continue
fi
fi
done
if [ -z "${DRIVER}" ]
then
echo "$(basename "$0"): error: no driver found for [${DSN}] in $(basename "${ODBC_INI}")"
exit 1
fi
# get filename of driver
echo "found driver named \"${DRIVER}\""
if [ -d "${DRIVER}" ] || [ ! -x "${DRIVER}" ]
then
# not a filename, look it up
DRIVERNAME=${DRIVER}
ODBC_INST="${ODBC_DIR}/odbcinst.ini"
echo "\"${DRIVERNAME}\" is not an executable file"
echo "looking for entry named [${DRIVERNAME}] in ${ODBC_INST}"
grep "${DRIVERNAME}" "${ODBC_INST}" > /dev/null
if [ $? -ne 0 ]
then
if [ $? -eq 1 ]
then
echo "$(basename "$0"): error: no driver entry [${DRIVERNAME}] in ${ODBC_INST}"
fi
exit 1;
fi
CMD="/^\[${DRIVERNAME}\]/,/^[[:space:]]*$/ { s/^/ /; p; }"
DRIVER_LINE=$(sed -ne "${CMD}" "${ODBC_INST}" \
| grep -Ei '^[[:space:]]*driver[[:space:]]*=')
if [ -z "${DRIVER_LINE}" ]
then
echo "$(basename "$0"): no driver mentioned for [${DRIVERNAME}] in $(basename "${ODBC_INST}")"
exit 1
fi
echo " found driver line: \"${DRIVER_LINE}\""
DRIVER=$(echo "${DRIVER_LINE}" | awk -F ' *= *' '{print $2}')
if [ -z "${DRIVER}" ]
then
echo "$(basename "$0"): driver line incomplete for [${DRIVERNAME}] in $(basename "${ODBC_INST}")"
exit 1
fi
echo " found driver ${DRIVER} for [${DRIVERNAME}] in $(basename "${ODBC_INST}")"
fi
if [ -z "${DRIVER}" ]
then
echo "$(basename "$0"): error: sorry, failed sanity check: \${DRIVER} is null"
exit 1
fi
if [ -x "${DRIVER}" ]
then
echo "${DRIVER} is an executable file"
else
echo "${DRIVER} is not an executable file"
echo "$(basename "$0"): error: no driver found for ${DSN}"
exit 1
fi
# find the server/servername
SERVER_LINE=$(sed -ne "${SED_CMD}" "${ODBC_INI}" \
| grep -Ei '^[[:space:]]*server(name)*[[:space:]]*=')
ATTRIBUTE=$(echo "${SERVER_LINE}" | awk -F' *= *' '{print $1}')
if [ -z "${ATTRIBUTE}" ]
then
echo "$(basename "$0"): neither \"Server\" nor \"Servername\" found for [${DSN}] in $(basename "${ODBC_INI}")"
exit 1
fi
echo "${SERVER_LINE}" | grep -i servername >/dev/null
#
# Find the server's hostname
#
if [ $? -eq 0 ] # ODBC-Combined
then
TDS_SERVER=$(echo "${SERVER_LINE}" | awk -F ' *= *' '{print $2}')
echo 'Using ODBC-Combined strategy'
echo "DSN [${DSN}] has servername \"${TDS_SERVER}\" (from ${ODBC_INI})"
if [ -z "${TDS_SERVER}" ]
then
exit 1
fi
# Look for $TDS_SERVER in freetds.conf
FREETDS_DIR=$(tsql -C | grep 'freetds.conf directory' | awk -F: '{print $2}' | sed 's/^ *//')
if [ -z "${FREETDS_DIR}" ]
then
echo "$(basename "$0"): error: unable to locate directory for freetds.conf using \"$(command -v tsql)\""
exit 1
fi
for F in "${HOME}/.freetds.conf" "${FREETDS_DIR}/freetds.conf"
do
if [ -r "$F" ]
then
echo "$F is a readable file"
else
echo "cannot read \"$F\""
continue
fi
echo "looking for [${TDS_SERVER}] in $F"
grep -F "[${TDS_SERVER}]" "$F" > /dev/null
if [ $? -eq 0 ]
then
FREETDS_CONF=$F
break
else
echo "[${TDS_SERVER}] not found in $F"
fi
done
if [ -z "${FREETDS_CONF}" ]
then
echo "$(basename "$0"): error: unable to locate ${TDS_SERVER} in any freetds.conf"
exit 1
fi
# Examine server entry in freetds.conf
echo found this section:
SED_CMD="/^\[${TDS_SERVER}\]/,/^[[:space:]]*$/ { s/^/ /; p; }"
sed -ne "${SED_CMD}" "${FREETDS_CONF}"
SERVER_LINE=$(sed -ne "${SED_CMD}" "${FREETDS_CONF}" \
| grep -Ei '^[[:space:]]*host[[:space:]]*=')
# No character class support in mawk,
# cf. "Mawk does not support Posix character classes in expressions"
# https://bugs.launchpad.net/ubuntu/+source/mawk/+bug/69724
HOST=$(echo "${SERVER_LINE}" | awk -F' *= *' '{print $2}')
if [ -z "${HOST}" ]
then
echo "$(basename "$0"): no \"host\" entry found for [${TDS_SERVER}] in $(basename "${FREETDS_CONF}")"
exit 1
fi
else # odbc.ini contains a "server", a DNS host
HOST=$(echo "${SERVER_LINE}" | awk -F ' *= *' '{print $2}')
echo "\"${ATTRIBUTE}\" found, not using freetds.conf"
echo "${ATTRIBUTE} is \"${HOST}\""
if [ -z "${HOST}" ]
then
echo "$(basename "$0"): no value found for \"${ATTRIBUTE}\" entry in $(basename "${ODBC_INI}")"
exit 1
fi
fi
# If the "host" is an ip address, look up the name, for neatness, e.g.
## $ host 10.81.36.39
## 39.36.81.10.IN-ADDR.ARPA domain name pointer ntc5003.eg.com
if [ "${HOST}" = "$(echo "${HOST}" | sed 's/[^.0-9]*//')" ]
then
ADDRESS=${HOST}
echo "looking up hostname for ip address ${ADDRESS}"
HOST=$(host "${HOST}" | awk '/domain/ {print $5}' | sed 's/\.$//')
if [ -z "${HOST}" ]
then
echo "$(basename "$0"): warning: no DNS hostname found for \"${ADDRESS}\""
HOST=${ADDRESS} # restore host address string
fi
fi
# Now we have a DNS hostname for the server in HOST
if [ "${HOST}" != "${ADDRESS}" ]
then
ADDRESS=$(host "${HOST}" | awk '/has address/ {print $4}' | head -1)
fi
if [ -z "${ADDRESS}" ]
then
echo "$(basename "$0"): no IP address found for \"${HOST}\""
exit 1
fi
#cho ${HOST} has address ${ADDRESS}
# Report what we know and exec isql
printf "\n"
printf "Configuration looks OK. Connection details:\n\n"
printf "%22s:\t%-30s\n" DSN "${DSN}"
printf "%22s:\t%-30s\n" odbc.ini "${ODBC_INI}"
printf "%22s:\t%-30s\n" Driver "${DRIVER}"
printf "%22s:\t%-30s\n" "Server hostname" "${HOST}"
printf "%22s:\t%-30s\n" Address "${ADDRESS}"
printf "\n"
echo "Attempting connection as ${USERNAME} ..."
if [ -z "${TDSDUMP}" ]
then
TDSDUMP_AUTO="/tmp/$(basename "$0").dump.$$"
export TDSDUMP=${TDSDUMP_AUTO}
fi
( set -x; isql "${DSN}" "${USERNAME}" "${PASSWORD}" -v ) \
|| sed -ne 's/Connecting/FAILED &/p' "${TDSDUMP}"
test "${TDSDUMP_AUTO}" && rm -f "${TDSDUMP_AUTO}"
Zerion Mini Shell 1.0