#!/bin/bash

#  Copyright (c) 2003-2005, Burton M. Strauss III - Burton@ntopsupport.com

#
#  Return the distro name, release # or both...
#
#    Crude, but marginally effective, uses the /etc/xxxxxx-release file.
#
# V1 Tested:   RH 7.2 7.3, 8.0, 9, 2.1AS 2.1ES, 3.0AS, 3.0ES
#              Fedora Core 1, 2, 3
#              Mandrake 9.1, 10, 10.1
#              Debian 2.2 3.0(Woody)
#              Gentoo 
#              Slackware 8.1.01
#              SuSE 7.1 7.2a 8.0ES 8.2, 9.0ES, 9.0
#              LFS (Linux From Scratch)
#              FreeBSD 4.9, 4.10, 5.2, 5.3
#              NetBSD 1.6
# V2 Tested:
#              DamnSmallLinux 0.9.0, 0.9.2
#              Debian 3.0r3, 3.1
#              Fedora Core 2, 3
#              FreeBSD 4.11, 5.3
#              Gentoo 2005.0
#              Knoppix 3.7
#              RedHat 8.0
#              SuSE 8.0ES, 9.0, 9.2
#              Ubuntu 5.04
#
# 2005/09 Tested:
#              CentOS 4.1
#              Fedora Core 3
#              FreeBSD 5.4
#              Knoppix
#              RedHat 9
#              SuSE 9.3
#
# 2008/01 Tested:
#              Ubuntu 7.10 - Gutsy
#

#  Released under GPL...

#    This program 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.
#   
#    This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

function checkForKeyFile() {
    # The tests for release, version etc. file...
    for testme in fedora-release *-release *version lfs-*; do
      releaseFile=`find /etc -name "${testme}" ${maxdepth} 2> /dev/null | \
                   grep -v lsb | \
                   grep -v UnitedLinux | \
                   head -n 1` 
      if test "x${releaseFile}" != "x"; then
        if test "x${debug}" = "xY"; then
          echo "DEBUG01: /etc found ${releaseFile}"
        fi
        return
      fi
    done
}

function checkForStandards() {
    # Check for the 'standards' bodies id files...
    lsbFile=`find /etc -name "lsb-release" ${maxdepth} 2> /dev/null | \
             head -n 1`
    if test "x${debug}" = "xY"; then
        echo "DEBUG04: /etc/lsb-release found ${lsbFile}"
    fi
    if test "x${lsbFile}" != "x"; then
        if test -f ${lsbFile}; then
            # Grab the release name
            . ${lsbFile}
            lsbrelease=${LSB_VERSION}
            if test "x${debug}" = "xY"; then
                echo "DEBUG05: lsb release is ${lsbrelease}"
            fi
        else
            lsbrelease="LSB release unavailable"
        fi
    else
        lsbrelease="Not identified as LSB compliant"
    fi
    
    unitedFile=`find /etc -name "UnitedLinux-release" ${maxdepth} 2> /dev/null | \
                head -n 1`
    if test "x${debug}" = "xY"; then
        echo "DEBUG06: /etc/UnitedLinux-release found ${unitedFile}"
    fi
    if test "x${unitedFile}" != "x"; then
        if test -f ${unitedFile}; then
            # Grab the release name
            unitedrelease=`cat ${unitedFile} | \
                           head -n 1 | \
                           awk '{ for (i=1; i<=NF; i++) { if (0 + $i != 0) { print $i } } }'`
            if test "x${debug}" = "xY"; then
                echo "DEBUG07: UnitedLinux release is ${unitedrelease}"
            fi
        else
            unitedrelease="United Linux release unavailable"
        fi
    else
        unitedrelease="Not identified as UnitedLinux compliant"
    fi
}

function checkEtcIssue() {    
    # Try /etc/issue...
    eirelease=`awk '{ for(i=1; i<=NF; i++) { if((0+$i) != 0) { print $i; exit 0 } } }' /etc/issue`
    if test "x${debug}" = "xY"; then
      echo "DEBUG20: /etc/issue gives ${eirelease}"
    fi
    eidistro=`awk '{ print $1; exit 0 }' /etc/issue`
    if test "x${debug}" = "xY"; then
      echo "DEBUG21: /etc/issue gives ${eidistro}"
    fi

    if test "x${releaseFile}" = "x"; then
      release="${eirelease}"
      distro="${eidistro}"
      releaseFile="/etc/issue"
      if test "x${debug}" = "xY"; then
        echo "DEBUG22: /etc/issue sets distro/release/releaseFile"
      fi
      return
    fi

    if test "x${release}" = "x"; then
      if test "x${eirelease}" != "x"; then
        release="${eirelease}"
        if test "x${debug}" = "xY"; then
          echo "DEBUG23: /etc/issue sets release"
        fi
      fi
    fi
    if test "x${distro}" = "x"; then
      if test "x${eidistro}" != "x"; then
        distro="${eidistro}"
        if test "x${debug}" = "xY"; then
          echo "DEBUG24: /etc/issue sets distro"
        fi
      fi
    fi
}

function processReleaseFile() {

    if test "x${releaseFile}" = "x/etc/issue"; then
      return
    fi

    if test ! -f ${releaseFile} ; then
      return
    fi

    # Grab the distro name...
    distro=`echo ${releaseFile} | \
            awk '{ i=index($0, "_"); \
                   if (i == 0) { \
                       i=index($0, "-") \
                   }; \
                   print tolower(substr($0, 6, i-6)) \
                 }'`
    if test "x${debug}" = "xY"; then
        echo "DEBUG11: Distribution is ${distro}"
    fi

    # Check if the file is readable for a release name?
    if test -s ${releaseFile}; then
    
        # Grab the full release name text
        fullrelease=`cat ${releaseFile} | \
                     head -n 1`
        if test "x${debug}" = "xY"; then
            echo "DEBUG12: fullrelease is ${fullrelease}"
        fi
    
        # Grab the release name
        release=`cat ${releaseFile} | \
                 head -n 1 | \
                 awk '{ i=index($0, "("); if(i>0) { $0 = substr($0, 1, i-1) }; for (i=1; i<=NF; i++) { if (0 + $i != 0) { print $i } } }'`
    
        if test "x${release}" = "x"; then
            if test "x${debug}" = "xY"; then
                echo "DEBUG13: (alt) Scanning for VERSION in ${releaseFile}"
            fi
            release=`cat ${releaseFile} | \
                     grep -i VERSION | \
                     head -n 1 | \
                     awk '{ i=index($0, "("); if(i>0) { $0 = substr($0, 1, i-1) }; for (i=1; i<=NF; i++) { if (0 + $i != 0) { print $i } } }'`
        fi
    
        if test "x${release}" = "x"; then
            if test "x${debug}" = "xY"; then
                echo "DEBUG14: (alt) Executing set commands in ${releaseFile}"
            fi
            . ${releaseFile} 2> /dev/null
            release="${VERSION}"
        fi
    
        if test "x${release}" = "x"; then
            release="unknown"
            if test "x${debug}" = "xY"; then
                echo "DEBUG15: Unable to identify release"
            fi
        else
            if test "x${debug}" = "xY"; then
                echo "DEBUG16: Release is ${release}"
            fi
        fi

        return
    fi
    
    # Can't grab the release name, so maybe it's in the filename?
    release=`echo ${releaseFile} | \
           awk '{ i=index($0, "_"); \
                   if (i == 0) { \
                       i=index($0, "-") \
                   }; \
                   if (i == 0) { \
                       print "" \
                   } else \
                       print tolower(substr($0, i+1)) \
                }'`

    if test "x${release}" = "x"; then
        # else return unknown
        release="unknown"
        if test "x${debug}" = "xY"; then
            echo "DEBUG17: File unreadable, release unknown"
        fi
    fi

    return
}

function processDebianDerivatives() {    
    # Debian derivatives...
    if test "${distro}x" = "debianx"; then
      if test "x${debug}" = "xY"; then
        echo "DEBUG18: Debian derivatives... distro ${distro} release ${release} full ${fullrelease}..."
      fi
      baserelease=" (base: ${distro} ${release})"
      # DamnSmall Linux? /usr/share/doc/dsl directory...
      if test -d /usr/share/doc/dsl; then
        distro="DamnSmallLinux" 
        if test -r /usr/share/doc/dsl/getting_started.html; then
          release=`awk '{ i=index($0, "Version"); if(i == 0) { next }; $0 = substr($0, i+7); i=index($0, "<"); if(i == 0) { next }; $0=substr($0, 1, i-1); print $1; exit 0; }' /usr/share/doc/dsl/getting_started.html` 
          if test "x${debug}" = "xY"; then
            echo "DEBUG19: DamnSmallLinux release is ${release}"
          fi
        fi
        fullrelease="${distro} ${release}${baserelease}"
        return
      fi

      if test -d /KNOPPIX; then
        distro="Knoppix"
        release="unknown"
        fullrelease="${distro} ${release}${baserelease}"
        return
      fi

      if test "x${eirelease}" != "x"; then
        if test "x${eirelease}" != "x${release}"; then
          # /etc/issue different ... use that...
          release="${eirelease}"
          distro="${eidistro}"
          fullrelease="${distro} ${release}${baserelease}"
          return
        fi
      fi
    fi
}

function processRedhatDerivatives() {    
    # Redhat derivatives...
    if test "${distro}x" = "redhatx"; then
      if test "x${debug}" = "xY"; then
        echo "DEBUG25: Redhat derivatives... distro ${distro} release ${release} full ${fullrelease}..."
      fi
      baserelease=" (base: ${distro} ${release})"
      case "${fullrelease}" in
        [Cc]ent[Oo][Ss]*)
          distro="Centos"
          fullrelease="${distro} ${release}${baserelease}"
          return
          ;;
      esac
    fi
}

debug="N"
if test "x${1}" = "x--debug"; then
    debug="Y"
    shift
fi

quiet="N"
if test "x${1}" = "x--quiet"; then
    quiet="Y"
    shift
fi

find . -maxdepth 1 >/dev/null 2>/dev/null
rc=$?
if test $rc -eq 0; then
  maxdepth=" -maxdepth 1"
else
  maxdepth=""
fi

# Is this even Linux??
case `uname -s` in
  [Ll]inux*)
    kernel=`uname -r`

    checkForKeyFile

    checkForStandards
    
    # Now if we're still not found, let's use the standards bodies files... if we have 'em
    if test "x${releaseFile}" = "x"; then
        if test "x${unitedFile}" != "x"; then
            releaseFile="${unitedFile}"
            if test "x${debug}" = "xY"; then
                echo "DEBUG08: Using UnitedLinux file for release"
            fi
        elif test "x${lsbFile}" != "x"; then
            releaseFile="${lsbFile}"
            if test "x${debug}" = "xY"; then
                echo "DEBUG09: Using LSB file for release"
            fi
        fi
    fi

    checkEtcIssue

    # Still not found?  Um... unknown...
    if test "x${releaseFile}" = "x"; then
        distro="Linux"
        release="unknown"
        if test "x${debug}" = "xY"; then
            echo "DEBUG10: Unknown linux release"
        fi
    else
        processReleaseFile
    fi

    case $distro in
      [Rr]ed[Hh]at) 
        processRedhatDerivatives
        ;;
      [Dd]ebian)
        processDebianDerivatives
        ;;
    esac
    ;;

  [Ff][Rr][Ee][Ee][Bb][Ss][Dd])
    # FreeBSD
    if test "x${debug}" = "xY"; then
      echo "DEBUGF1: Limited tests for FreeBSD..."
    fi
    distro=`uname -s`
    if test "x${debug}" = "xY"; then
      echo "DEBUGF2: uname -s: ${distro}"
    fi
    release=`uname -r`
    if test "x${debug}" = "xY"; then
      echo "DEBUGF3: uname -r: ${release}"
    fi
    kernel=`uname -i 2> /dev/null`
    rc=$?
    if test "x${debug}" = "xY"; then
      echo "DEBUGF4: uname -i: ${kernel}"
    fi
    if test "x${rc}" != "x0"; then
        fullkernel=`uname -v | awk '{ print $NF }'`
        if test "x${debug}" = "xY"; then
          echo "DEBUGF5: Full kernel: ${fullkernel}"
        fi
        kernel=`echo ${fullkernel} | \
                awk '{ i=index($0, "/"); \
                       while(i>0) { \
                           $0 = substr($0, i+1); \
                           i=index($0, "/"); \
                       }; \
                       print $0 }'`
        if test "x${debug}" = "xY"; then
          echo "DEBUGF6: gives kernel: ${kernel}"
        fi
    fi

    fullrelease="${distro} ${release}"
    lsbrelease="Not Linux - not LSB compliant"
    unitedrelease="Not Linux - not UnitedLinux compliant"
    ;;

  *)
    # Not Linux - oops
    if test "x${quiet}" != "xY"; then
        echo "WARNING: This routine only works under Linux/FreeBSD.  We'll fake it as best we can!"
    fi
    distro=`uname -s`
    if test "x${debug}" = "xY"; then
      echo "DEBUGX1: uname -s gives 'distro': ${distro}"
    fi
    release=`uname -r`
    if test "x${debug}" = "xY"; then
      echo "DEBUGX1: uname -r gives 'release': ${release}"
    fi
    kernel="unknown"
    fullrelease="unknown"
    lsbrelease="Not Linux - not LSB compliant"
    unitedrelease="Not Linux - not UnitedLinux compliant"
    ;;
esac

case "${1}" in
  *-d*)
    echo ${distro}
    ;;
  *-r*)
    echo ${release}
    ;;
  *-k*)
    echo ${kernel}
    ;;
  *-f*)
    echo ${fullrelease}
    ;;
  *-l*)
    echo ${lsbrelease}
    ;;
  *-u*)
    echo ${unitedrelease}
    ;;
  -*)
       echo
       echo "Usage: linuxrelease [--distro] [--[united|lsb|full]release] [--kernel] [--help]"
       echo
       echo "  Uses the /etc/xxxxx-release or /etc/xxxxx_version or other files to figure out "
       echo "  a decent guess as to which Linux distro and release this is..."
       echo
    ;;
  *)
    echo ${distro} release ${release} kernel ${kernel}
    ;;
esac
