#!/bin/sh # # lsb_release - collect LSB conformance status about a system # # Copyright (C) 2000, 2002, 2004 Free Standards Group, Inc. # Originally by Dominique MASSONIE # # 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. # # * Changes in 2.0 # - Support LSB 2.0 module layout (Mats Wichmann) # The LSB_VERSION is now a colon-separated field of supported module versions # An /etc/lsb-release.d is searched for modules beyond the core. # Only the filenames in this directory is looked at, those names are added # to LSB_VERSION. This allows module support to be handled easily by # package install/removal without a need to edit lsb-release on the fly. # - Correct license: FSG == Free Standards Group, Inc. # # * Changes in 1.4 # - "awk" not needed anymore (Loic Lefort) # - fixed bug #121879 reported by Chris D. Faulhaber, # some shells doesn't support local variables # - fixed a bug when single parameter sets many args including -s # - function DisplayProgramVersion (undocumented) now exits script like Usage # - cosmetic changes in comments/outputs # # * Changes in 1.3 # - No changes in script, only in build infrastructure # # * Changes in 1.2 # - Fixed more bash'isms # - LSB_VERSION is no longer required in /etc/lsb-release file # # * Changes in 1.1 # - removed some bash-ism and typos # Notice: script remains broken with ash because of awk issues # - changed licence to FSG - "Free Software Group, Inc" # - fixed problem with --short single arg call # - changed Debian specifics, codename anticipates release num # # Description: # Collect information from sourceable /etc/lsb-release file (present on # LSB-compliant systems) : LSB_VERSION, DISTRIB_ID, DISTRIB_RELEASE, # DISTRIB_CODENAME, DISTRIB_DESCRIPTION (all optional) # Then (if needed) find and add names from /etc/lsb-release.d # Then (if needed) find and parse the /etc/[distro]-release file ############################################################################### # DECLARATIONS ############################################################################### # This script version SCRIPTVERSION="2.0" # Defines the data files INFO_ROOT="/etc" # directory of config files INFO_LSB_FILE="lsb-release" # where to get LSB version INFO_LSB_DIR="lsb-release.d" # where to get LSB addon modules INFO_DISTRIB_SUFFIX="release" # - ALTERNATE_DISTRIB_FILE="/etc/debian_version" # for Debian [based distrib] ALTERNATE_DISTRIB_NAME="Debian" # " CHECKFIRST="/etc/redhat-release" # check it before file search # Defines our exit codes EXIT_STATUS="0" # default = Ok :) ERROR_UNKNOWN="10" # unknown error ERROR_USER="1" # program misuse ERROR_PROGRAM="2" # internal error ERROR_NOANSWER="3" # all required info not available # typically non LSB compliant distro! # Defines our messages MSG_LSBVER="LSB Version:\t" MSG_DISTID="Distributor ID:\t" MSG_DISTDESC="Description:\t" MSG_DISTREL="Release:\t" MSG_DISTCODE="Codename:\t" MSG_NA="n/a" MSG_NONE="(none)" MSG_RESULT="" # contains the result in case short output selected # Description string delimiter DESCSTR_DELI="release" ############################################################################### # FUNCTIONS ############################################################################### # Display Program Version for internal use (needed by help2man) DisplayProgramVersion() { echo "FSG `basename $0` v$SCRIPTVERSION" echo echo "Copyright (C) 2000, 2002, 2004 Free Standards Group, Inc." echo "This is free software; see the source for copying conditions. There\ is NO" echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR\ PURPOSE." echo echo "Originally written by Dominique MASSONIE." exit $EXIT_STATUS } # defines the Usage for lsb_release Usage() { echo "FSG `basename $0` v$SCRIPTVERSION prints certain LSB (Linux\ Standard Base) and" echo "Distribution information." echo echo "Usage: `basename $0` [OPTION]..." echo "With no OPTION specified defaults to -v." echo echo "Options:" echo " -v, --version" echo " Display the version of the LSB specification against which the distribution is compliant." echo " -i, --id" echo " Display the string id of the distributor." echo " -d, --description" echo " Display the single line text description of the distribution." echo " -r, --release" echo " Display the release number of the distribution." echo " -c, --codename" echo " Display the codename according to the distribution release." echo " -a, --all" echo " Display all of the above information." echo " -s, --short" echo " Use short output format for information requested by other options (or version if none)." echo " -h, --help" echo " Display this message." exit $EXIT_STATUS } # Handles the enhanced args (i.e. --something) EnhancedGetopt() { getopt -T >/dev/null 2>&1 # is getopt the enhanced one ? if [ $? = 4 ] then # Yes, advanced args ALLOWED OPT=$(getopt -o acdhirsvp \ --long all,codename,description,help,id,release,short,version,program_version \ -n 'lsb_release' \ -- "$@") else # No, advanced args NOT allowed # convert (if needed) the enhanced options into basic ones MYARGS=$(echo "$@" | sed -e "/--/s/-\(-[[:alnum:]]\)[[:alnum:]]*/\1/g") OPT=$(getopt -o acdhirsvp \ -n 'lsb_release' \ -- "$MYARGS") fi if [ $? != 0 ] then exit $ERROR_PROGRAM fi NB_ARG="" # enabled if many args set in one parameter (i.e. -dris) eval set -- "$OPT" while true ; do case "$1" in -a|--all) ARG_A="y"; NB_ARG="y"; shift;; -c|--codename) ARG_C="y"; NB_ARG="y"; shift;; -d|--description) ARG_D="y"; NB_ARG="y"; shift;; -i|--id) ARG_I="y"; NB_ARG="y"; shift;; -r|--release) ARG_R="y"; NB_ARG="y"; shift;; -s|--short) ARG_S="y"; shift;; -v|--version) ARG_V="y"; NB_ARG="y"; shift;; -p|--program_version) DisplayProgramVersion;; -h|--help) Usage;; --) shift; break;; *) EXIT_STATUS=$ERROR_USER Usage;; esac done } # Get/Init LSB infos (maybe Distrib infos too) GetLSBInfo() { if [ -f "$INFO_ROOT/$INFO_LSB_FILE" ] then # should init at least LSB_VERSION . "$INFO_ROOT/$INFO_LSB_FILE" fi if [ -z "$LSB_VERSION" ] then LSB_VERSION=$MSG_NA else # if we found LSB_VERSION, continue to look in directory if [ -d "$INFO_ROOT/$INFO_LSB_DIR" ] then for tag in "$INFO_ROOT/$INFO_LSB_DIR/"* do LSB_VERSION=$LSB_VERSION:`basename $tag` done fi fi } # Get the whole distrib information string (from ARG $1 file) InitDistribInfo() { ## Notice: Debian has a debian_version file ## (at least) Mandrake has two files, a mandrake and a redhat one FILENAME=$1 # CHECKFIRST or finds' result in GetDistribInfo() or "" if [ -z "$FILENAME" ] then if [ -f "$ALTERNATE_DISTRIB_FILE" ] then # For Debian only [ -z "$DISTRIB_ID" ] && DISTRIB_ID="$ALTERNATE_DISTRIB_NAME" [ -z "$DISTRIB_RELEASE" ] \ && DISTRIB_RELEASE=$(cat $ALTERNATE_DISTRIB_FILE) [ -z "$DISTRIB_CODENAME" ] && [ "$DISTRIB_RELEASE" = "2.1" ] \ && DISTRIB_CODENAME="Slink" [ -z "$DISTRIB_CODENAME" ] && [ "$DISTRIB_RELEASE" = "2.2" ] \ && DISTRIB_CODENAME="Potato" # [ -z "$DISTRIB_CODENAME" ] && [ "$DISTRIB_RELEASE" = "2.3" ] \ # && DISTRIB_CODENAME="Woody" [ -z "$DISTRIB_CODENAME" ] && DISTRIB_CODENAME=$DISTRIB_RELEASE # build the DISTRIB_DESCRIPTION string (never need to be parsed) [ -z "$DISTRIB_DESCRIPTION" ] \ && DISTRIB_DESCRIPTION="$DISTRIB_ID $DESCSTR_DELI $DISTRIB_REL\ EASE ($DISTRIB_CODENAME)" else # Only for nothing known compliant distrib :( [ -z "$DISTRIB_ID" ] && DISTRIB_ID=$MSG_NA [ -z "$DISTRIB_RELEASE" ] && DISTRIB_RELEASE=$MSG_NA [ -z "$DISTRIB_CODENAME" ] && DISTRIB_CODENAME=$MSG_NA [ -z "$DISTRIB_DESCRIPTION" ] && DISTRIB_DESCRIPTION=$MSG_NONE EXIT_STATUS=$ERROR_NOANSWER fi else NO="" # is Description string syntax correct ? if [ -z "$DISTRIB_DESCRIPTION" ] \ || [ -n "$(echo $DISTRIB_DESCRIPTION | \ sed -e "s/.*$DESCSTR_DELI.*//")" ] then TMP_DISTRIB_DESC=$(head -n 1 $FILENAME 2>/dev/null) [ -z "$DISTRIB_DESCRIPTION" ] \ && DISTRIB_DESCRIPTION=$TMP_DISTRIB_DESC else TMP_DISTRIB_DESC=$DISTRIB_DESCRIPTION fi if [ -z "$TMP_DISTRIB_DESC" ] # head or lsb-release init then # file contains no data DISTRIB_DESCRIPTION=$MSG_NONE NO="y" else # Do simple check [ -n "$(echo $TMP_DISTRIB_DESC | \ sed -e "s/.*$DESCSTR_DELI.*//")" ] \ && NO="y" fi if [ -n "$NO" ] then # does not contain "release" delimiter [ -z "$DISTRIB_ID" ] && DISTRIB_ID=$MSG_NA [ -z "$DISTRIB_RELEASE" ] && DISTRIB_RELEASE=$MSG_NA [ -z "$DISTRIB_CODENAME" ] && DISTRIB_CODENAME=$MSG_NA fi fi } # Check missing and requested infos, then find the file and get infos GetDistribInfo() { NO="" # /etc/lsb-release data are enough to reply what is requested? [ -n "$ARG_D" ] && [ -z "$DISTRIB_DESCRIPTION" ] && NO="y" [ -z "$NO" ] && [ -n "$ARG_I" ] && [ -z "$DISTRIB_ID" ] && NO="y" [ -z "$NO" ] && [ -n "$ARG_R" ] && [ -z "$DISTRIB_RELEASE" ] && NO="y" [ -z "$NO" ] && [ -n "$ARG_C" ] && [ -z "$DISTRIB_CODENAME" ] && NO="y" if [ -n "$NO" ] then if [ ! -f "$CHECKFIRST" ] then CHECKFIRST=$(find $INFO_ROOT/ -maxdepth 1 \ -name \*$INFO_DISTRIB_SUFFIX \ -and ! -name $INFO_LSB_FILE \ -and -type f \ 2>/dev/null \ | head -n 1 ) # keep one of the files found (if many) fi InitDistribInfo $CHECKFIRST fi } # Display version of LSB against which distribution is compliant DisplayVersion() { if [ -z "$ARG_S" ] then echo -e "$MSG_LSBVER$LSB_VERSION" # at least "n/a" else MSG_RESULT="$MSG_RESULT${MSG_RESULT:+ }$LSB_VERSION" fi } # Display string id of distributor ( i.e. a single word! ) DisplayID() { if [ -z "$DISTRIB_ID" ] then ## Linux could be part of the distro name (i.e. Turbolinux) or a separate word ## set before, after... ## also expect a delimiter ( i.e. "release" ) if [ -n "$(echo $TMP_DISTRIB_DESC | sed "s/.*$DESCSTR_DELI.*//")" ] then DISTRIB_ID=$MSG_NA else DISTRIB_ID=$(echo " $TMP_DISTRIB_DESC" \ | sed -e "s/[[:blank:]][Ll][Ii][Nn][Uu][Xx][[:blank:]]/ /g" \ -e "s/\(.*\)[[:blank:]]$DESCSTR_DELI.*/\1/" -e "s/[[:blank:]]//g") fi fi if [ -z "$ARG_S" ] then echo -e "$MSG_DISTID$DISTRIB_ID" else MSG_RESULT="$MSG_RESULT${MSG_RESULT:+ }$DISTRIB_ID" fi } # Diplay single line text description of distribution DisplayDescription() { if [ -z "$DISTRIB_DESCRIPTION" ] then # should not be empty since GetDistribInfo called on Initialization ! EXIT_STATUS=$ERROR_PROGRAM fi if [ -z "$ARG_S" ] then echo -e "$MSG_DISTDESC$DISTRIB_DESCRIPTION" else MSG_RESULT="$MSG_RESULT${MSG_RESULT:+ }\"$DISTRIB_DESCRIPTION\"" fi } # Display release number of distribution. DisplayRelease() { if [ -z "$DISTRIB_RELEASE" ] then # parse the "$DISTRIB_DESCRIPTION" string DISTRIB_RELEASE=$(echo "$TMP_DISTRIB_DESC" | \ sed -e "s/.*$DESCSTR_DELI[[:blank:]]*\([[:digit:]][[:graph:]]*\).*/\1/" ) [ "$DISTRIB_RELEASE" = "$TMP_DISTRIB_DESC" ] \ || [ -z "$DISTRIB_RELEASE" ] \ && DISTRIB_RELEASE=$MSG_NA fi if [ -z "$ARG_S" ] then echo -e "$MSG_DISTREL$DISTRIB_RELEASE" else MSG_RESULT="$MSG_RESULT${MSG_RESULT:+ }$DISTRIB_RELEASE" fi } # Display codename according to distribution version. DisplayCodename() { if [ -z "$DISTRIB_CODENAME" ] then # parse the "$DISTRIB_DESCRIPTION" string DISTRIB_CODENAME=$(echo "$TMP_DISTRIB_DESC" | \ sed -e "s/.*$DESCSTR_DELI.*(\(.*\)).*/\1/") [ "$DISTRIB_CODENAME" = "$TMP_DISTRIB_DESC" ] \ || [ -z "$DISTRIB_CODENAME" ] \ && DISTRIB_CODENAME=$MSG_NA fi if [ -z "$ARG_S" ] then echo -e "$MSG_DISTCODE$(echo "$DISTRIB_CODENAME" | \ tr -d "[:blank:]")" # Remove blanks else MSG_RESULT="$MSG_RESULT${MSG_RESULT:+ }$(echo "$DISTRIB_CODENAME" | \ tr -d "[:blank:]")" fi } ############################################################################### # MAIN ############################################################################### # Check if any prog argument if [ -z "$1" ] then ARG_V="y" # default set to Display LSB Version (not Usage) else EnhancedGetopt "$@" # Parse program args if [ -n "$ARG_S" ] && [ -z "$NB_ARG" ] then ARG_V="y" # set also default for --short when single arg fi fi # Update args to All if requested if [ -n "$ARG_A" ] then [ -z "$ARG_C" ] && ARG_C="y" [ -z "$ARG_D" ] && ARG_D="y" [ -z "$ARG_I" ] && ARG_I="y" [ -z "$ARG_R" ] && ARG_R="y" [ -z "$ARG_V" ] && ARG_V="y" fi # Initialization GetLSBInfo GetDistribInfo # Display requested infos (order as follow) [ -n "$ARG_V" ] && DisplayVersion [ -n "$ARG_I" ] && DisplayID [ -n "$ARG_D" ] && DisplayDescription [ -n "$ARG_R" ] && DisplayRelease [ -n "$ARG_C" ] && DisplayCodename [ -n "$ARG_S" ] && echo "$MSG_RESULT" exit $EXIT_STATUS