
# --8<--8<--8<--8<--
#
# Copyright (C) 2006 Smithsonian Astrophysical Observatory
#
# This file is part of sysarch
#
# sysarch is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# sysarch is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
#       Free Software Foundation, Inc.
#       51 Franklin Street, Fifth Floor
#       Boston, MA  02110-1301, USA
#
# -->8-->8-->8-->8--


###############################################################################
# Clean up OS name and OSrev...

# versions may have several levels of hierarchy: a.b.c.d limit it to
# two levels.
#
# sets global variables os_version, os_version_maj and os_version_min
function simplify_os_version {

    # work by stripping off levels from the left.  this makes no
    # assumptions as to the number of levels greater than two
    local version=$1

    os_version_maj=${version%%.*}

    if [ "$os_version_maj" = "$version" ]; then

		os_version="$os_version_maj"
		os_version_min=
		os_version="$version"

    else

		local minor="${version#*.}"
		os_version_min="${minor%%.*}"
		os_version="$os_version_maj.$os_version_min"

    fi
}

# check that an OS version is legal.  for now that means that it
# starts with a digit and only contains digits, periods, dashes and
# underscores
function check_os_version {

	[[ "$1" =~ ^[0-9][0-9_.\-]*$ ]]
}

# map release names to versions. usually only needed when
# running pre-release versions

function map_os_version {

	case "$os_vendor" in

		[dD]ebian* )

			case "$1" in

				'lenny/sid' )
					os_version=5.0
					;;

				'squeeze/sid' )
					os_version=6.0
					;;

				'wheezy/sid' )
					os_version=7.0
					;;

				'jessie/sid' )
					os_version=8.0
					;;

			esac
			;;

		Ubuntu* )

			case "$1" in

				'quantal' )
					os_version=12.10
					;;

			esac
			;;

		* )
			os_version="$1"
			;;
	esac


}

case "$OS" in

  Linux)

    os_type=linux


    #-------------------------
    # First get kernel version.  Usually it's something like x.y.z,
    # but Fedora Core might give you x.y.z.w.
    # define kern_version_maj=x.y

    kern_version=${_uname_r%%-*}
    kern_version_min=${kern_version#*.*.}
    kern_version_maj=${kern_version%.$kern_version_min}
    kern_versions="${kern_version}:${kern_version_maj}"

    #----------------------
    # Now get glibc version

    _libc_dir=/lib

    # support multi-arch on debian based distributions
    if command -v dpkg-architecture > /dev/null ; then

        # dpkg-architecture uses CC as part of its process finding
        # a compiler to get the architecture.  make it use the default
        # one to avoid problems if CC is set and unusuable
	_libc_dir=/lib/$(env -u CC dpkg-architecture -qDEB_HOST_MULTIARCH)

    elif [ -e /lib64 ] ; then

	_libc_dir=/lib64

    fi

    _libc=$_libc_dir/libc.so.*
    if [ -x $_libc ]; then
      _IFS="$IFS"; IFS=$'\n'
      _glibc_ver=( $( $_libc ) )
      IFS="$_IFS"

      if [[ $_glibc_ver == *'stable release version '* ]] ; then
	  _glibc_ver=${_glibc_ver##*stable\ release\ version\ }
	  _glibc_ver=${_glibc_ver%,*}

      else
	  _glibc_ver=${_glibc_ver##*([!0-9])}
	  _glibc_ver=${_glibc_ver%%*([!0-9])}
      fi


      # 3.2.1 => 3
      _glibc_maj=${_glibc_ver%%.*}

      # 3.2.1 => 2.1 => 2
      # NOT 3.2.1 => 3.2 => 2, as it might start as 3.2

      _glibc_min=${_glibc_ver#*.}
      _glibc_min=${_glibc_min%%.*}

    elif [ -a /usr/include/features.h ]; then

      _tmp=($(echo __GLIBC__ __GLIBC_MINOR__ \
               | cpp -imacros /usr/include/features.h -P -E -))

      _glibc_maj=${_tmp[0]}
      _glibc_min=${_tmp[1]}
      _glibc_ver=${_glibc_maj}.${_glibc_min}

    else

      die "Unable to determine glibc version!"

    fi

    #----------------------------------------------------------
    # user space version (glibc)

    os_uversion="${_glibc_ver}"
    os_uversion_maj="${_glibc_maj}.${_glibc_min}"

    if [ $os_uversion != $os_uversion_maj ] ; then
	os_uversions[0]="$os_uversion"
    fi

    _min=$_glibc_min
    while (( _min > 2 ))
    do
      os_uversions[${#os_uversions[*]}]="${_glibc_maj}.${_min}"
      (( _min = _min - 1 ))
    done

    _IFS="$IFS"; IFS=:
    os_uversions="${os_uversions[*]}"
    IFS="$_IFS"


    #----------------------------------------------------------
    # Now get vendor/distribution name and version

    while true ; do

	if [ -f /etc/issue ]; then

	    exec 4< /etc/issue
	    read -u 4 _issue
	    _issue_a=( $_issue )
	    case "$_issue" in

		Debian* )
		    os_vendor=debian
			map_os_version "${_issue_a[2]}"
		    ;;

		CentOS* )
		    os_vendor=CentOS
			map_os_version "${_issue_a[2]}"
		    ;;

		Ubuntu* )
		    os_vendor=Ubuntu
			map_os_version "${_issue_a[1]}"
		    ;;

		Red\ Hat\ Enterprise\ Linux* )
		    os_vendor=RHEL
		    map_os_version ${_issue_a[6]}
		    ;;

	    esac

	    simplify_os_version "$os_version"
	    check_os_version "$os_version" && break
	fi

        # brute force debian, 'cause lsb_release on debian runs apt-cache,
        # which takes forever
	if [ "$os_vendor" = debian -a -f /etc/debian_version ]; then

	    exec 4< /etc/debian_version
	    read -u 4 os_version
	    exec 4<&-
	    map_os_version "$os_version"
	    simplify_os_version $os_version

	    # backwards compatibility
	    [ "$os_version" = 3.1 ] && \
		os_vendor=Debian

	    check_os_version "$os_version" && break

	fi

	# Slackware
	if [ -f /etc/slackware-version ]; then
	    exec 4< /etc/slackware-version
	    read -u 4 os_vendor _os_version
	    exec 4<&-
	    simplify_os_version "${_os_version}"
	    check_os_version "$os_version" && break
	fi

        # try LSB
	if  command -v lsb_release > /dev/null; then

	    _tmp=($(lsb_release -s -r -i))
	    os_vendor=${_tmp[0]}
	    os_version=${_tmp[1]}

	    case "$os_vendor" in
		*Fedora* )
		   # previously mistakenly labeled Fedora 8
		   # as FedoraCore.  Gotta keep it that way for backwards
	           # compatibility.
		    if [ $os_version -lt 9 ]; then
			os_vendor=RHFC
		    else
			os_vendor=RHF
		    fi
		    ;;

		RedHatEnterprise* )
	            os_vendor=RHEL
		    ;;

		CentOS* )
	            os_vendor=CentOS
		    ;;

		Debian )
		    os_vendor=debian
		    # If it's Debian, testing & unstable versions don't cut it
		    # go for /etc/debian_version
		    if [ $os_version = testing -o $os_version = unstable ]; then
			map_os_version $(< /etc/debian_version)
		        # don't care about the revision e.g.: "4.0r?"
		        os_version=${os_version%r?}
		    fi
		    ;;

	    esac

	    simplify_os_version $os_version
	    check_os_version "$os_version" && break

	fi

        # brute force redhat?

	if [ -f /etc/redhat-release ]; then

	    _tmp=$(< /etc/redhat-release)

	    case "$_tmp" in
		*Fedora*    ) os_vendor=RHFC ;;
		*Enterprise*) os_vendor=RHEL ;;
		*Red\ Hat*  ) os_vendor=RH ;;
	    esac

	    os_version=${_tmp##*elease }
	    os_version=${os_version%% *}
	    simplify_os_version $os_version
	    check_os_version "$os_version" && break
	fi

        # no clue
	die "unable to determine Linux version"

    done

    case "$os_vendor" in

        # For CentOS, RHEL & Debian, minor versions should be compatible
	RHEL | RockyLinux | CentOS | debian  )

	    os_versions="${os_version_maj}:${os_version}"
	    (( _min = os_version_min - 1 ))
	    while (( _min >= 0 ))
	    do
		os_versions[${#os_versions[*]}]="${os_version_maj}.${_min}"
		(( _min = _min - 1 ))
	    done

	    _IFS="$IFS"; IFS=:
	    os_versions="${os_versions[*]}"
	    IFS="$_IFS";

	    ;;


	* )
	    # so far no differences between major and minor versions
	    os_version_maj=$os_version
	    os_versions=$os_version
	    ;;

    esac


    ;;

  SunOS)
	 # backwards compatibility.  should be "solaris"
	 OS=SunOS

	 os_type=solaris
	 os_vendor=sun


	 os_version=$_uname_r
	 os_version_maj=${os_version%.*}
	 os_version_min=${os_version##*.}

	 # Solaris has OS versions of 5.X.  Anything else we don't
	 # support (as if there really are any SunOS systems out
	 # there...)

	 if [ "$os_version_maj" != 5 ]; then
	   die "Unexpected Solaris major version: $os_version_maj"
	 fi

	 # There doesn't seem to be any "minor" version information
	 # that's easily accessible or parseable.  In fact, what is parsed
	 # out as os_version_min above is really the "major" version
	 # (e.g. Solaris 7,8,9,10)  We should just toss the "5." prefix,
	 # but for historical compatibility we'll leave it in.

	 os_version_maj="$os_version_min"

	 # Solaris is pretty backwards compatible, so construct a list
	 # of versions from 5.X back to 5.5
	 os_versions=$os_version
	 (( _maj = os_version_maj - 1 ))
	 while (( _maj > 5 ))
	 do
	   os_versions="${os_versions}:5.${_maj}"
	   (( _maj = _maj - 1 ))
	 done

	 # add the horribly generic "5" prefix for backwards
	 # compatibility. new environments shouldn't depend upon it.
	 os_versions="${os_versions}:5"

	 # add back in the 5. prefix
	 os_version_maj="5.$os_version_maj"

	 os_uversion=$os_version
	 os_uversion_maj=$os_uversion
	 os_uversions=$os_versions

	 kern_version=$(uname -v)
	 kern_version_maj=$kern_version
	 ;;

  Darwin)
	  OS=darwin
	  os_type=$OS
	  os_vendor=apple

	  os_version=$(sw_vers -productVersion)
	  # ensure there's a triad of values
	  test ${os_version%.*} = ${os_version%%.*} \
	      && os_version="${os_version}.0"

	  os_version_maj=${os_version%.*}
	  os_versions="${os_version}:${os_version_maj}"

	  os_uversion=$os_version
	  os_uversion_maj=${os_uversion%.*}
	  os_uversions=$os_versions

	  kern_version=${_uname_r}
	  kern_version_maj=${kern_version%.*}
	  kern_versions="${kern_version}:${kern_version_maj}"

	  ;;


  *)
     die "unknown operating system: $OS"

esac

# fall through

test -z "$os_versions" \
 && os_versions=$os_version

test -z "$kern_versions" \
 && kern_versions=$kern_version

