#!/bin/sh
# osname: Get the operating system dependent name.
#
# Christos Zoulas, Tue Jun 11 14:07:28 EDT 1996
# 1996-06-11  Kimmo Suominen
#
# @(#)osname.sh,v 1.26 2011/10/21 17:53:22 kim Exp
#

export PATH
PATH=/bin:/usr/bin

###############################################################################
# RESEARCH FUNCTIONS
###############################################################################

discoverosrelease()
{
    # Use the kernel name and release by default.
    os=$(uname -s)
    release=$(uname -r)

    # By default we are using the major version of the release.
    minmaj=major

    # Stock SVR4 uses the nodename as the kernel name.
    # The nodename can be FQDN while the kernel name is short.
    case $(uname -n) in
    "${os}"|"${os}".*)
	case "${release}" in
	4.*)
	    os=svr4
	    # The major version is not useful at this point,
	    # so use the minor version instead.
	    minmaj=minor
	    ;;
	esac
    esac

    # Figure out release version and a usable kernel name or its substitute.
    case "${os}" in
    CYGWIN_*-*)
	# Cygwin returns the kernel version as part of the kernel name.
	# We end up ignoring the Cygwin version information.
	release=$(echo "${os}" | sed -e 's/^[^-]*-//')
	os=$(echo "${os}" | sed -e 's/-.*//')
	;;
    Darwin)
	# Check for Mac OS.
	os=$(sw_vers -productName 2> /dev/null)
	if [ $? = 0 ]
	then
	    release=$(sw_vers -productVersion)
	    case "${os}" in
	    "Mac OS "*)
		# Truncate e.g. "Mac OS X"
		os=macos
		;;
	    esac
	else
	    os=darwin
	fi
	;;
    IRIX*)
	# Truncate e.g. IRIX64
	os=irix
	;;
    Linux)
	# Linux is not sufficient as an operating system name.
	# Install the following packages:
	# - Debian, Ubuntu: lsb-release
	# - Fedora, RedHat: redhat-lsb
	release=$(lsb_release -sr 2> /dev/null)
	if [ $? = 0 ]
	then
	    case "${release}" in
	    *.*)
		# This release version looks fully qualified.
		;;
	    *)
		# Maybe we can find a better release version from files.
		# E.g. SUSE doesn't include the patchlevel in the version
		# reported by lsb_release.
		hackfromfiles
		;;
	    esac
	    os=$(lsb_release -si)
	else
	    hackfromfiles
	fi
	case "${os}" in
	Fedora*)
	    # Truncate e.g. FedoraCore
	    os=fedora
	    ;;
	Mandriva*)
	    # Truncate e.g. MandrivaLinux
	    os=mandriva
	    ;;
	RedHat*)
	    # Truncate e.g. RedHatEnterpriseServer or RedHatEnterpriseES
	    os=redhat
	    ;;
	SUSE*)
	    # Truncate e.g. "SUSE LINUX"
	    os=suse
	    ;;
	esac
	;;
    OSF*)
	# Truncate e.g. OSF1
	os=osf
	;;
    SunOS)
	case "${release}" in
	[0-4]*)
	    os=sunos
	    ;;
	*)
	    os=solaris
	    ;;
	esac
	;;
    esac

    # Checked OK:
    # - Kernel: CYGWIN_NT, Darwin, FreeBSD, NetBSD, OpenBSD
    # - Linux LSB Distribution: CentOS, Debian, Ubuntu
    os=$(echo "${os}" | tr '[A-Z]' '[a-z]' | tr -cd '[_a-z0-9]')
}

# If we don't have lsb_release on Linux, become desperate.
# We do want to try all files: they should be ordered so
# that more preferred information comes first (especially
# for the name).
hackfromfiles()
{
    local file i nos
    for file in \
	/etc/fedora-release \
	/etc/redhat-release \
	/etc/SuSE-release \
	/etc/issue \
	/etc/debian_version \
	;
    do
	if [ -r "${file}" ]
	then
	    set -- $(head -1 "${file}")
	    for i
	    do
		case "${i}" in
		CentOS|Debian|Fedora*|Mandriva*|RedHat*|SUSE|SuSE|Ubuntu)
		    case "${os}" in
		    Linux)
			os="${i}"
			;;
		    esac
		    ;;
		[0-9]*)
		    release="${i}"
		    ;;
		esac
	    done
	    case "${os}" in
	    Linux)
		nos=$(basename "${file}" | sed -e 's/[-_](release|version)$//')
		case "${nos}" in
		issue)
		    ;;
		*)
		    os="${nos}"
		    ;;
		esac
		;;
	    esac
	    case "${file}" in
	    /etc/SuSE-release)
		release=$(awk -vMAJ="${release}" -vMIN=0 '
		    /VERSION/ { MAJ = $NF; }
		    /PATCHLEVEL/ { MIN = $NF; }
		    END { print MAJ "." MIN }
		' "${file}")
		;;
	    esac
	    release=$(echo "${release}" | tr -cd '[0-9.]' | sed -e 's/\.$//')
	fi
    done
}

###############################################################################
# OUTPUT FUNCTIONS
###############################################################################

# Use uname to get the processor type. We could try to use uname -p, but 
# that works only on Solaris and NetBSD. So we use uname -m instead and
# fix the amd64, i86pc and sun4* output.
machname()
{
    local machine=$(uname -m)
    case "${machine}" in
    i[23456]86)
	echo i386
	;;
    i86pc)
	# SunOS
	echo i386
	;;
    sun4*)
	# SunOS
	echo sparc
	;;
    x86_64)
	echo amd64
	;;
    *)
	echo "${machine}" | tr '[A-Z]' '[a-z]'
	;;
    esac
}

# Lowercase and otherwise simplify the kernel name (or its substitute).
osname()
{
    echo "${os}"
}

# Extract release version number.
# We define this as the major and minor version.
# The micro version is usually not significant when grouping machines.
release()
{
    echo "${release}.0.0" \
    | case "${minmaj}" in
    minor)
	cut -d. -f2-3
	;;
    *)
	cut -d. -f1-2
    esac
}

# Full version number.
update()
{
    echo "${release}"
}

# Extract version numbers.
version()
{
    echo "${release}.0" \
    | case "${minmaj}" in
    minor)
	cut -d. -f2
	;;
    *)
	cut -d. -f1
	;;
    esac
}

###############################################################################
# USAGE
###############################################################################

# Keeping usage last, close to the parsing.
usage()
{
    local PROG=${0##*/}
    cat <<EOF 1>&2
Usage:	${PROG} [-format <format>]
	${PROG} -group|-machine|-os|-release|-relgroup|-path
	${PROG} -all|-a
EOF
}

###############################################################################
# MAIN PROGRAM
###############################################################################

# Process arguments.
format=''
needformat=false
for i
do
    newformat=''
    if ${needformat}
    then
	newformat="${i}"
	needformat=false
    else
	case "${i}" in
	-all|-a)
	    # Dump all fields
	    newformat=all
	    ;;
	-format)
	    # Custom format
	    needformat=true
	    ;;
	-group)
	    newformat='%n-%m'
	    ;;
	-help|--help)
	    usage
	    exit 0
	    ;;
	-machine)
	    newformat='%m'
	    ;;
	-os)
	    newformat='%n.%v'
	    ;;
	-release)
	    newformat='%n-%r'
	    ;;
	-relgroup)
	    newformat='%n-%r-%m'
	    ;;
	-path)
	    newformat='%n.%v.%m'
	    ;;
	*)
	    usage
	    exit 1
	    ;;
	esac
    fi
    if [ -n "${newformat}" ]
    then
	if [ -n "${format}" ]
	then
	    usage
	    exit 1
	else
	    format="${newformat}"
	fi
    fi
done

discoverosrelease

if [ -n "${format}" ]
then
    if [ "${format}" = "all" ]
    then
	printf "OS Name: " ; osname
	printf "Version: " ; version
	printf "Release: " ; release
	printf "Update:  " ; update
	printf "Machine: " ; machname
    else
	echo "${format}" | sed \
	    -e "s,%m,$(machname),g" \
	    -e "s,%n,$(osname),g" \
	    -e "s,%r,$(release),g" \
	    -e "s,%u,$(update),g" \
	    -e "s,%v,$(version),g" \
	    ;
    fi
else
    osname
fi
