#!/bin/bash
#/**
#@file     System.lib
#@brief    Librería o clase System
#@class    System
#@brief    Funciones básicas del sistema.
#@version  1.1.0
#@warning  License: GNU GPLv3+
#*/


#/**
#         ogEcho [str_logtype ...] [str_loglevel] "str_message" ...
#@brief   Muestra mensajes en consola y lo registra en fichero de incidencias.
#@param   str_logtype  tipo de registro de incidencias.
#@param   str_loglevel nivel de registro de incidencias.
#@param   str_message  mensaje (puede recibir más de 1 parámetro.
#@return  Mensaje mostrado.
#@warning Si no se indica nivel de registro, solo muestra mensaje en pantalla.
#@warning Si DEBUG="no", no se registran mensajes de error.
#@note    logfile = { log, command, session }; usa "log" si se indica nivel de registro.
#@note    loglevel = { help, info, warning, error }
#@note    El nivel de ayuda \c (help) no se registra en el fichero de incidencias.
#@version 0.9 - Primera versión para OpenGnSys
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2009-07-23
#@version 1.0.5 - Elegir fichero de log.
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2014-03-17
#@version 1.1.0 - Posibilidad de no registrar mensajes en ficheros.
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2015-11-10
#*/
function ogEcho () {

# Variables locales
local CONT=1 LOGS LOGLEVEL DATETIME

# Selección de ficheros de rgistro de incidencias.
while [ $CONT ]; do
    case "${1,,}" in
        log)     LOGS="$LOGS $OGLOGFILE";    shift ;;
        command) LOGS="$LOGS $OGLOGCOMMAND"; shift ;;
        session) LOGS="$LOGS $OGLOGSESSION"; shift ;;
        *)       CONT= ;;
    esac
done

# Selección del nivel de registro (opcional).
case "${1,,}" in
     help)    shift ;;
     info)    LOGLEVEL="$1"; shift ;;
     warning) LOGLEVEL="$1"; shift ;;
     error)   LOGLEVEL="$1"; shift ;;
     *)       ;;
esac

if [ -n "$LOGLEVEL" ]; then
    DATETIME=$(date +"%F %T")
    # Registrar mensajes en fichero de log si la depuración no está desactivada.
    [ "${DEBUG,,}" != "no" ] && LOGS="$OGLOGFILE $LOGS"
    logger -s -t "OpenGnsys $LOGLEVEL" "$DATETIME $*" 2>&1 | tee -a $LOGS
else
    echo "$*" | tee -a $LOGS
fi
}


#/**
#         ogExecAndLog str_logfile ... str_command ...
#@brief   Ejecuta un comando y guarda su salida en fichero de registro.
#@param   str_logfile     fichero de registro (pueden ser varios).
#@param   str_command     comando y comandos a ejecutar.
#@return  Salida de ejecución del comando.
#@note    str_logfile = { LOG, SESSION, COMMAND }
#@version 1.0.6 - Primera versión para OpenGnSys
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2013-07-02
#*/
function ogExecAndLog () {

# Variables locales
local ISCOMMAND ISLOG ISSESSION COMMAND CONTINUE=1 FILES REDIREC

# Si se solicita, mostrar ayuda.
if [ "$*" == "help" ]; then
    ogHelp "$FUNCNAME str_logfile ... str_command ..." \
           "$FUNCNAME COMMAND ls -al /"
    return
fi

# Procesar parámetros.
while [ $CONTINUE ]; do
    case "${1,,}" in
        command) ISCOMMAND=1; shift ;;
        log)     ISLOG=1; shift ;;
        session) ISSESSION=1; shift ;;
        *)       COMMAND="$@"
                 CONTINUE= ;;
    esac
done
# Error si no se recibe un comando que ejecutar.
[ -n "$COMMAND" ] || ogRaiseError $OG_ERR_FORMAT || return $?

# Componer lista de ficheros de registro.
if [ $ISCOMMAND ]; then
    FILES="$OGLOGCOMMAND"
    > $FILES
    REDIREC="2>&1"
fi
[ $ISLOG ] && FILES="$FILES $OGLOGFILE"
[ $ISSESSION ] && FILES="$FILES $OGLOGSESSION"

# Ejecutar comando.
eval $COMMAND $REDIREC | tee -a $FILES
# Salida de error del comando ejecutado.
return ${PIPESTATUS[0]}
}


#/**
#         ogGetCaller
#@brief   Devuelve nombre del programa o script ejecutor (padre).
#@param   No.
#@return  str_name - Nombre del programa ejecutor.
#@version 0.10 - Primera versión para OpenGnSys.
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2011-01-17
#*/
function ogGetCaller () {

# Obtener el nombre del programa o del script que ha llamado al proceso actual.
basename "$(COLUMNS=200 ps hp $PPID -o args | \
            awk '{if ($1~/bash/ && $2!="") { print $2; }
                  else { sub(/^-/,"",$1); print $1; } }')"
}


#/**
#         ogHelp ["str_function" ["str_format" ["str_example" ... ]]]
#@brief   Muestra mensaje de ayuda para una función determinda.
#@param   str_function Nombre de la función.
#@param   str_format   Formato de ejecución de la función.
#@param   str_example  Ejemplo de ejecución de la función.
#@return  str_help - Salida de ayuda.
#@note    Si no se indican parámetros, la función se toma de la variable \c $FUNCNAME
#@note    La descripción de la función se toma de la variable compuesta por \c MSG_FUNC_$función incluida en el fichero de idiomas.
#@note    Pueden especificarse varios mensajes con ejemplos.
#@version 0.9 - Primera versión para OpenGnSys.
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2009-07-27
#*/
function ogHelp () {

# Variables locales.
local FUNC MSG

# Mostrar función, descripción y formato.
FUNC="${1:-${FUNCNAME[${#FUNCNAME[*]}-1]}}"
MSG="MSG_HELP_$FUNC"
ogEcho help "$MSG_FUNCTION $FUNC: ${!MSG}"
[ -n "$2" ] && ogEcho help "    $MSG_FORMAT: $2"
# Mostrar ejemplos (si existen).
shift 2
while [ $# -gt 0 ]; do
    ogEcho help "    $MSG_EXAMPLE: $1"
    shift
done
}


#/**
#         ogRaiseError [str_logtype ...] int_errcode ["str_errmessage" ...]
#@brief   Devuelve el mensaje y el código de error correspondiente.
#@param   str_logtype    tipo de registro de incidencias.
#@param   int_errcode    código de error.
#@param   str_errmessage mensajes complementarios de error.
#@return  str_message - Mensaje de error, incluyendo las funciones relacionadas.
#@warning No definidas
#@note    Mensajes internacionales del fichero de idiomas.
#@version 0.9 - Primera versión para OpenGnSys.
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2009-07-21
#@version 1.0.5 - Muestra en el mensaje todas las funciones relacionadas (separadas por <-).
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2014-03-17
#*/ 
function ogRaiseError () {

# Variables locales
local CONT=1 LOGS MSG CODE FUNCS

# Si se solicita, mostrar ayuda.
if [ "$*" == "help" ]; then
    ogHelp "$FUNCNAME" "$FUNCNAME [str_logfile ...] int_errorcode str_errormessage"
    return
fi

# Selección de rgistros de incidencias.
while [ $CONT ]; do
    case "${1,,}" in
        log|command|session)  LOGS="$LOGS $1"; shift ;;
        *)                    CONT= ;;
    esac
done

# Obtener código y mensaje de error.
CODE="$1"
case "$CODE" in
     $OG_ERR_FORMAT)     MSG="$MSG_ERR_FORMAT \"$2\"" ;;
     $OG_ERR_NOTFOUND)   MSG="$MSG_ERR_NOTFOUND \"$2\"" ;;
     $OG_ERR_OUTOFLIMIT) MSG="$MSG_ERR_OUTOFLIMIT \"$2\"" ;;
     $OG_ERR_PARTITION)  MSG="$MSG_ERR_PARTITION \"$2\"" ;;
     $OG_ERR_LOCKED)     MSG="$MSG_ERR_LOCKED \"$2\"" ;;
     $OG_ERR_CACHE)      MSG="$MSG_ERR_CACHE \"$2\"" ;;
     $OG_ERR_NOGPT)      MSG="$MSG_ERR_NOGPT \"$2\"" ;;
     $OG_ERR_REPO)	 MSG="$MSG_ERR_REPO \"$2\"" ;;
     $OG_ERR_FILESYS)    MSG="$MSG_ERR_FILESYS \"$2\"" ;;
     $OG_ERR_IMAGE)      MSG="$MSG_ERR_IMAGE \"$2\"" ;;
     $OG_ERR_NOTOS)      MSG="$MSG_ERR_NOTOS \"$2\"" ;;
     $OG_ERR_NOTEXEC)    MSG="$MSG_ERR_NOTEXEC \"$2\"" ;;
     $OG_ERR_NOTWRITE)   MSG="$MSG_ERR_NOTWRITE \"$2\"" ;;
     $OG_ERR_NOTCACHE)   MSG="$MSG_ERR_NOTCACHE \"$2\"" ;;
     $OG_ERR_CACHESIZE)  MSG="$MSG_ERR_CACHESIZE \"$2\"" ;;
     $OG_ERR_REDUCEFS)   MSG="$MSG_ERR_REDUCEFS \"$2\"" ;;
     $OG_ERR_EXTENDFS)   MSG="$MSG_ERR_EXTENDFS \"$2\"" ;;
     $OG_ERR_IMGSIZEPARTITION)   MSG="$MSG_ERR_IMGSIZEPARTITION \"$2\"" ;;   
     $OG_ERR_UPDATECACHE)       MSG="$MSG_ERR_UPDATECACHE \"$2\"" ;;
     $OG_ERR_DONTFORMAT)	MSG="$MSG_ERR_DONTFORMAT \"$2\"" ;;
     $OG_ERR_IMAGEFILE)   MSG="$MSG_ERR_IMAGEFILE \"$2\"" ;;
     $OG_ERR_UCASTSYNTAXT)   MSG="$MSG_ERR_UCASTSYNTAXT \"$2\"" ;;
     $OG_ERR_UCASTSENDPARTITION)   MSG="$MSG_ERR_UCASTSENDPARTITION \"$2\"" ;;    
     $OG_ERR_UCASTSENDFILE)   MSG="$MSG_ERR_UCASTSENDFILE \"$2\"" ;;  
     $OG_ERR_UCASTRECEIVERPARTITION)   MSG="$MSG_ERR_UCASTRECEIVERPARTITION \"$2\"" ;;    
     $OG_ERR_UCASTRECEIVERFILE)   MSG="$MSG_ERR_UCASTRECEIVERFILE \"$2\"" ;;  
     $OG_ERR_MCASTSYNTAXT)   MSG="$MSG_ERR_MCASTSYNTAXT \"$2\"" ;;
     $OG_ERR_MCASTSENDFILE)   MSG="$MSG_ERR_MCASTSENDFILE \"$2\"" ;;
     $OG_ERR_MCASTRECEIVERFILE)   MSG="$MSG_ERR_MCASTRECEIVERFILE \"$2\"" ;; 
     $OG_ERR_MCASTSENDPARTITION)   MSG="$MSG_ERR_MCASTSENDPARTITION \"$2\"" ;;
     $OG_ERR_MCASTRECEIVERPARTITION)   MSG="$MSG_ERR_MCASTRECEIVERPARTITION \"$2\"" ;; 
     $OG_ERR_PROTOCOLJOINMASTER)   MSG="$MSG_ERR_PROTOCOLJOINMASTER \"$2\"" ;;
     $OG_ERR_DONTMOUNT_IMAGE)	MSG="$MSG_ERR_DONTMOUNT_IMAGE \"$2\"" ;;
     $OG_ERR_DONTUNMOUNT_IMAGE)   MSG="$MSG_ERR_DONTUNMOUNT_IMAGE \"$2\"" ;;
     $OG_ERR_DONTSYNC_IMAGE)	MSG="$MSG_ERR_DONTSYNC_IMAGE \"$2\"" ;;
     $OG_ERR_NOTDIFFERENT)	MSG="$MSG_ERR_NOTDIFFERENT \"$2\"" ;;
     $OG_ERR_SYNCHRONIZING)	MSG="$MSG_ERR_SYNCHRONIZING \"$2\"" ;;
     $OG_ERR_NOTUEFI)		MSG="$MSG_ERR_NOTUEFI \"$2\"" ;;
     $OG_ERR_NOMSDOS)		MSG="$MSG_ERR_NOMSDOS \"$2\"" ;;
     $OG_ERR_NOTBIOS)		MSG="$MSG_ERR_NOTBIOS \"$2\"" ;;
     *)                  MSG="$MSG_ERR_GENERIC"; CODE=$OG_ERR_GENERIC ;;
esac

# Obtener lista de funciones afectadas, incluyendo el script que las llama.
FUNCS="${FUNCNAME[@]:1}"
FUNCS="${FUNCS/main/$(basename $0 2>/dev/null)}"

# Mostrar mensaje de error si es función depurable y salir con el código indicado.
if [ $CODE == $OG_ERR_FORMAT ] || ogCheckStringInGroup "$FUNCS" "$NODEBUGFUNCTIONS" || ! ogCheckStringInGroup "${FUNCS%% *}" "$NODEBUGFUNCTIONS"; then
    ogEcho $LOGS error "${FUNCS// /<-}: $MSG" >&2
fi
return $CODE
}


#/**
#         ogIsRepoLocked
#@brief   Comprueba si el repositorio está siendo usado (tiene ficheros abiertos).
#@param   No.
#@return  Código de salida: 0 - bloqueado, 1 - sin bloquear o error.
#@version 0.10 - Primera versión para OpenGnSys.
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2011-01-17
#@version 1.0.1 - Devolver falso en caso de error.
#@author  Ramon Gomez, ETSII Universidad de Sevilla
#@date    2011-05-18
#*/
function ogIsRepoLocked ()
{
# Variables locales.
local f FILES

# Si se solicita, mostrar ayuda.
if [ "$*" == "help" ]; then
    ogHelp "$FUNCNAME" "$FUNCNAME" "if $FUNCNAME; then ...; fi"
    return
fi

# No hacer nada, si no está definido el punto de montaje del repositorio.
[ -z "$OGIMG" ] && return 1

# Comprobar si alguno de los ficheros abiertos por los procesos activos está en el
# punto de montaje del repositorio de imágenes.
FILES=$(for f in /proc/[0-9]*/fd/*; do readlink -f "$f"; done | grep "^$OGIMG")   # */ (comentario Doxygen)
test -n "$FILES"
}


function ogCheckProgram ()
{
# Si se solicita, mostrar ayuda.
if [ "$*" == "help" ]; then
    ogHelp "$FUNCNAME \"str_program ...\"" \
           "$FUNCNAME \"partimage partclone mbuffer\""
    return
fi

# Error si no se recibe 1 parámetro.
[ $# == 1 ] || ogRaiseError $OG_ERR_FORMAT || return $?

local PERROR PLOG i
PERROR=0
PLOG=" "
for i in `echo $1`
do
  if [ ! `which $i` ] 
     then
     	PERROR=1
     	PLOG="$PLOG $i" 
     fi
done
if [ "$PERROR" == "1" ] 
then
	ogRaiseError $OG_ERR_NOTEXEC "$PLOG" || return $?
else    	
	return 0
fi
} 



#### PRUEBA
function ogIsVirtualMachine() {
case "$(dmidecode -s system-product-name)" in
    KVM|VirtualBox)
        return 1 ;;
    *)  return 0 ;;
esac
}

