ogboot/bin/oglivecli

729 lines
30 KiB
Bash

#!/bin/bash
#/**
#@file oglivecli
#@brief Command line tool to manage ogLive clients.
#@usage oglivecli Command [Options ...]
#@param Command:
#@param help show this help
#@param version show script version
#@param config [Parameter] show configuration parameters
#@param disk_usage show disk usage information
#@param list_installed_oglives list installed ogLive clients
#@param check_services_status check status of critical services
#@param download show a menu to download an ogLive ISO image from the OpenGnsys website
#@param download Iso download a specific ogLive ISO image from the OpenGnsys website
#@param install Iso install a new ogLive client from a downloaded ISO image
#@param uninstall uuid uninstall an ogLive client using its UUID
#@param get_default get index value for default ogLive client
#@param set_default uuid set default ogLive client using its UUID
#@param get_info uuid get JSON information about an installed ogLive client using its UUID
#@warning This script needs "jq" command.
#@version 3.0.0 - Updated with to adapt to Ogboot.
#@author Ramón M. Gómez - ETSII Univ. Sevilla
#@author Ramón M. Gómez - Qindel formacion y servicios SL
#@date 2024-08-06
#*/ ##
# Global constants definition.
PROG=$(basename "$(realpath "$0")") # Program name.
OPENGNSYS=/opt/ogboot # OpenGnsys main directory.
DOWNLOADDIR=$OPENGNSYS/lib # Directory to store ogLive images.
DOWNLOADURL="https://ognproject.evlt.uma.es/trac/downloads" # Download URL.
TFTPDIR=$OPENGNSYS/tftpboot/ # TFTP directory.
DEFOGLIVE="ogLive" # Default ogLive directory.
MINREL=20190601 # Mininum ogLive compatibility release.
INFOFILE=$OPENGNSYS/etc/ogliveinfo.json # Configuration file.
# Global and secondary functions.
source $OPENGNSYS/lib/ogfunctions.sh || exit 1
# Check consistency, showing configuration problems.
function check() {
local ERR=0 AUX INST DEF
[ $# -ne 0 ] && raiseError usage
# Check for old system that needs conversion.
if [ -z "$(stat -c "%N" $TFTPDIR/ogclient | awk '$3~/'$DEFOGLIVE'/ {print}')" ]; then
echo "This server uses old ogclient, please run \"$PROG convert\" to update."
let ERR++
[ ! -f $INFOFILE ] && return $ERR
fi
# Check for other problems.
[ ! -f $INFOFILE ] && echo "Configuration file does not exists: $INFOFILE" && let ERR++
[ -f $INFOFILE -a "$(jq -c keys $INFOFILE 2>/dev/null)" != "[\"default\",\"oglive\"]" ] && echo "Format error in configuration file: $INFOFILE" && let ERR++
[ ! -e $TFTPDIR ] && echo "TFTP directory does not exist: $TFTPDIR." && let ERR++
# Check for installed ogLive clients.
INST=( $(find $TFTPDIR/ -type d -name "$DEFOGLIVE-*" -a ! -name "*.old" -printf "%f\n" | sort) )
[[ ${#INST[@]} -eq 0 ]] && echo "No ogLive clients are installed." && let ERR++
DEF=( $(jq -r .oglive[].directory $INFOFILE 2>/dev/null | sort) )
# Compare installed and defined ogLive clients.
AUX=$(comm -23 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ogLive are installed but not defined: ${AUX//$'\n'/, }" && let ERR++
AUX=$(comm -13 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ogLive are defined but not installed: ${AUX//$'\n'/, }" && let ERR++
# Compare downloaded and defined ISO images.
INST=( $(find $DOWNLOADDIR/ -type f -name "$DEFOGLIVE-*.iso" -printf "%f\n" | sort) )
DEF=( $(jq -r .oglive[].iso $INFOFILE 2>/dev/null | sort) )
AUX=$(comm -23 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ISOs are downloaded but not defined: ${AUX//$'\n'/, }" && let ERR++
AUX=$(comm -13 <(printf "%s\n" ${INST[*]}) <(printf "%s\n" ${DEF[*]}))
[ -n "$AUX" ] && echo "Some ISOs are defined but not downloaded: ${AUX//$'\n'/, }" && let ERR++
# Check for new ISO files downloaded after installation.
AUX=$(jq -r '.oglive[] as $og | $og.iso + ":" + $og.directory' $INFOFILE 2>/dev/null | \
while IFS=":" read -r DEF INST; do
[ $DOWNLOADDIR/$DEF -nt $TFTPDIR/$INST ] && echo "$DEF"
done)
[ -n "$AUX" ] && echo "Some ISOs are downloaded after installation: ${AUX//$'\n'/, }" && let ERR++
AUX=$(jq -r '.oglive[] as $og | if ($og.revision[1:9] | tonumber) < '$MINREL' then $og.directory else "" end' $INFOFILE 2>/dev/null)
[ -n "$AUX" ] && echo "Some installed ogLive aren't fully compatible: ${AUX//$'\n'/, }" && let ERR++
DEF=$(jq -r ".oglive[$(getdefault)].directory" $INFOFILE 2>/dev/null)
INST=$(stat -c "%N" $TFTPDIR/$DEFOGLIVE | cut -f4 -d\')
[ "$DEF" != "$INST" ] && echo "Default ogLive is not linked to right directory: $DEF <> $INST" && let ERR++
# Print result.
[ $ERR -eq 0 ] && echo "OK!" || echo "Problems detected: $ERR"
return $ERR
}
# List installed ogLive clients.
function list() {
[ $# -ne 0 ] && raiseError usage
[ ! -r $INFOFILE ] && raiseError access "Configuration file."
# List all defined indexes, directories and check if missing.
jq -r .oglive[].directory $INFOFILE | nl -v 0 | \
awk '{system("echo -n "$0"; test -d '$TFTPDIR'/"$2" || echo -n \" (missing)\"; echo")}' | column -t
}
# Show information about an installed ogLive client.
function show() {
local INDEX
[ $# -ne 1 ] && raiseError usage
[ ! -r $INFOFILE ] && raiseError access "Configuration file."
# Show JSON entries.
case "$1" in
default) # Default index.
INDEX="[$(jq -r .default $INFOFILE)]" ;;
all) # All intries.
;;
[0-9]*) # Index.
INDEX="[$1]" ;;
*) # Directory.
INDEX="[$(search "$1" 2>/dev/null)]" || raiseError notfound "Directory \"$1\"."
;;
esac
jq ".oglive$INDEX" $INFOFILE || raiseError notfound "Index \"$1\"."
}
# Show index or directory corresponding to searching parameter.
function search() {
[ $# -ne 1 ] && raiseError usage
[ ! -r $INFOFILE ] && raiseError access "Configuration file."
# Show corresponding index or directory.
list | awk -v d="$1" '{if ($2==d) print $1; if ($1==d) print $2}' | grep . || raiseError notfound "Index/Directory \"$1\"."
}
function download() {
local OGLIVEFILE TARGETFILE SOURCELENGTH
# Verificar si el directorio de descarga existe y tiene permisos de escritura.
[ ! -d "$DOWNLOADDIR" ] && raiseError notfound "Directorio de descarga."
[ ! -w "$DOWNLOADDIR" ] && raiseError access "Directorio de descarga."
# Si no se proporciona ningún parámetro, mostrar el menú de descargas.
if [ -z "$1" ]; then
downloadMenu
else
local download_url="$1"
OGLIVEFILE=$(basename "$download_url")
# Validar que la URL apunte a un archivo ISO.
if [[ ! "$OGLIVEFILE" =~ \.iso$ ]]; then
raiseError download "La URL no apunta a un archivo ISO."
fi
# Obtener el tamaño de descarga.
SOURCELENGTH=$(curl -k --head --retry 5 --retry-delay 5 --max-time 30 "$download_url" | awk -F: '/Content-Length:/ {print $2}')
[ -n "$SOURCELENGTH" ] || raiseError download "No se pudo obtener el tamaño del archivo desde \"$download_url\"."
# Descargar ogLive.
TARGETFILE="$DOWNLOADDIR/$OGLIVEFILE"
trap "rm -f $TARGETFILE" 1 2 3 6 9 15
curl -k --retry 5 --retry-delay 5 "$download_url" -o "$TARGETFILE" || raiseError download "No se pudo descargar \"$OGLIVEFILE\"."
if [ -f "$TARGETFILE" ]; then
local file_type=$(file -b "$TARGETFILE")
if [[ "$file_type" =~ "ISO 9660" ]] && [[ "$file_type" =~ "ogClient" ]]; then
install "$OGLIVEFILE"
else
raiseError download "El archivo descargado no es un ogLive ISO válido."
fi
else
raiseError download "El archivo no fue descargado correctamente."
fi
fi
}
# Muestra un menú para seleccionar y descargar un archivo ogLive ISO del sitio web de OpenGnsys.
function downloadMenu() {
local OGLIVE NISOS i HTTPCODE ISOREL
OGLIVE=( $(curl -k --silent $DOWNLOADURL | grep "$DEFOGLIVE.*iso") )
NISOS=${#OGLIVE[@]}
local downloads=()
for i in $(seq 1 $NISOS); do
installed=false
compatible=false
# Obtener el nombre completo del archivo ISO
OGLIVEFILE=$(realpath "$DOWNLOADDIR/${OGLIVE[i-1]}")
# Extraer la distribución, revisión y arquitectura
OGLIVEDIST="$(echo $OGLIVEFILE | cut -f2 -d-)"
OGLIVEREV="${OGLIVEFILE##*-}"; OGLIVEREV="${OGLIVEREV%%.*}"
OGLIVEKRNL="$(echo $OGLIVEFILE | cut -f3- -d-)"; OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEREV.*}"
OGLIVEARCH="$(echo $OGLIVEFILE | awk -F- '{print $(NF-1)}')"
case "$OGLIVEARCH" in
i386|amd64)
OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEARCH}" ;;
*)
OGLIVEARCH="i386" ;;
esac
OGLIVEDIR="$TFTPDIR/$DEFOGLIVE-${OGLIVEKRNL%%-*}-$OGLIVEARCH-$OGLIVEREV"
OGLIVEDIR="${OGLIVEDIR/amd64-/}"
# Verificar si el ogLive está instalado y no es un directorio .old
if [ -d "$OGLIVEDIR" ] && [[ ! "$OGLIVEDIR" =~ \.old$ ]]; then
installed=true
else
installed=false
fi
ISOREL=${OGLIVE[i-1]##*-r}; ISOREL=${ISOREL%%.*}
[ $ISOREL -ge $MINREL ] && compatible=true
local DATA=$(jq -n \
--arg id "$i" \
--arg filename "${OGLIVE[i-1]}" \
--argjson installed "$installed" \
--argjson compatible "$compatible" \
'{id: $id, filename: $filename, installed: $installed, compatible: $compatible}')
downloads+=("$DATA")
done
jq -n --argjson downloads "$(printf '%s\n' "${downloads[@]}" | jq -s .)" \
'{downloads: $downloads}'
}
# Show a menu to select and download an ogLive ISO image from the OpenGnsys website.
function download_old() {
local OGLIVE NISOS i HTTPCODE TARGETFILE
local ISOREL
[ $# -gt 1 ] && raiseError usage
[ ! -d $DOWNLOADDIR ] && raiseError notfound "Download directory."
[ ! -w $DOWNLOADDIR ] && raiseError access "Download directory."
# Check parameter.
if [ -n "$1" ]; then
# ogLive to download.
OGLIVEFILE="$1"
else
# Show download menu.
OGLIVE=( $(curl -k --silent $DOWNLOADURL | grep "$DEFOGLIVE.*iso") )
NISOS=${#OGLIVE[@]}
echo "Available downloads (+ = installed, * = full compatibility):"
for i in $(seq 1 $NISOS); do
[ -e $DOWNLOADDIR/${OGLIVE[i-1]} ] && OGLIVE[i-1]="(+) ${OGLIVE[i-1]}"
ISOREL=${OGLIVE[i-1]##*-r}; ISOREL=${ISOREL%%.*}
[ $ISOREL -ge $MINREL ] && OGLIVE[i-1]="(*) ${OGLIVE[i-1]}"
done
select opt in "${OGLIVE[@]}"; do
[ -n "$opt" ] && OGLIVEFILE=${opt##* } && break
done
fi
# Get download size.
SOURCELENGTH=$(curl -k --head --retry 5 --retry-delay 5 --max-time 30 $DOWNLOADURL/$OGLIVEFILE | awk -F: '/Content-Length:/ {print $2}')
[ -n "$SOURCELENGTH" ] || raiseError download "$OGLIVEFILE"
# Download ogLive.
TARGETFILE=$DOWNLOADDIR/$OGLIVEFILE
trap "rm -f $TARGETFILE" 1 2 3 6 9 15
curl -k --retry 5 --retry-delay 5 --max-time 30 $DOWNLOADURL/$OGLIVEFILE -o $TARGETFILE || raiseError download "\"$OGLIVEFILE\"."
}
update_json() {
local key=$1
local value=$2
result_json=$(jq --arg key "$key" --arg value "$value" '.[$key] = $value' <<< "$result_json")
}
add_message() {
local message=$1
result_json=$(jq --arg message "$message" '.messages += [$message]' <<< "$result_json")
}
# Install an ogLive client from a previously downloaded ISO image.
function install() {
local OGLIVEFILE OGLIVEDIST OGLIVEREV OGLIVEKRNL OGLIVEDIR OGINITRD OGSQFS OGCLIENT=ogclient
local COMPRESS SAMBAPASS TMPDIR RSYNCSERV RSYNCCLNT JSON_OUTPUT
[ $# -ne 1 ] && { echo "{\"status\": \"error\", \"error\": \"usage\"}"; exit 1; }
OGLIVEFILE=$(realpath $DOWNLOADDIR/$1)
[ $(echo $OGLIVEFILE | wc -w) -gt 1 ] && { echo "{\"status\": \"error\", \"error\": \"usage\"}"; exit 1; }
[ ! -f $OGLIVEFILE ] && { echo "{\"status\": \"error\", \"error\": \"not found $1.\"}"; exit 1; }
[ ! -r $OGLIVEFILE ] && { echo "{\"status\": \"error\", \"error\": \"access $1.\"}"; exit 1; }
[ ! -w $(dirname $INFOFILE) ] && { echo "{\"status\": \"error\", \"error\": \"access configuration directory.\"}"; exit 1; }
[ ! -w $TFTPDIR ] && { echo "{\"status\": \"error\", \"error\": \"access installation directory.\"}"; exit 1; }
[ -z "$(file -b $OGLIVEFILE | grep "ISO.*ogClient")" ] && { echo "{\"status\": \"error\", \"error\": \"File is not an ogLive ISO image.\"}"; exit 1; }
OGLIVEDIST="$(echo $OGLIVEFILE|cut -f2 -d-)"
OGLIVEREV="${OGLIVEFILE##*-}"; OGLIVEREV="${OGLIVEREV%%.*}"
OGLIVEKRNL="$(echo $OGLIVEFILE|cut -f3- -d-)"; OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEREV.*}"
OGLIVEARCH="$(echo $OGLIVEFILE|awk -F- '{print $(NF-1)}')"
case "$OGLIVEARCH" in
i386|amd64)
OGLIVEKRNL="${OGLIVEKRNL%-$OGLIVEARCH}" ;;
*)
OGLIVEARCH="i386" ;;
esac
OGLIVEDIR="$TFTPDIR/$DEFOGLIVE-${OGLIVEKRNL%%-*}-$OGLIVEARCH-$OGLIVEREV"
OGLIVEDIR="${OGLIVEDIR/amd64-/}"
#OGLIVEDIR="$TFTPDIR/$DEFOGLIVE-$OGLIVEDIST-$OGLIVEKRNL-$OGLIVEARCH-$OGLIVEREV"
OGINITRD=$OGLIVEDIR/oginitrd.img
# Imprimir los valores de las variables
echo "OGLIVEFILE: $OGLIVEFILE"
echo "OGLIVEDIST: $OGLIVEDIST"
echo "OGLIVEKRNL: $OGLIVEKRNL"
echo "OGLIVEARCH: $OGLIVEARCH"
echo "OGLIVEREV: $OGLIVEREV"
echo "OGLIVEDIR: $OGLIVEDIR"
echo "OGINITRD: $OGINITRD"
# Pausar la ejecución para que el usuario revise los valores
read -p "Presione cualquier tecla para continuar con la instalación..."
[ ! -r $OGINITRD ] && OGINITRD=$TFTPDIR/$DEFOGLIVE/oginitrd.img
if [ -r $OGINITRD ]; then
echo "Tipo de compresión: $COMPRESS"
COMPRESS=$(file -b "$OGINITRD" | awk '{print tolower($1);}')
SAMBAPASS=$($COMPRESS -dc $OGINITRD | \
cpio -i --to-stdout scripts/ogfunctions 2>/dev/null | \
sed -n '/^[ \t].*OPTIONS=/s/.*pass=\(\w*\).*/\1/p')
echo "Contraseña de Samba extraída: $SAMBAPASS"
fi
rm -fr ${OGLIVEDIR}.old 2>/dev/null
mv -f $OGLIVEDIR ${OGLIVEDIR}.old 2>/dev/null
# Changes to a generic TMPDIR name
#TMPDIR=/tmp/${OGLIVEFILE%.iso}
TMPDIR=/tmp/$DOWNLOADDIR/ogLive
# TMPDIR for SQUASHFS mount
TMPDIR_SQUASHFS=/tmp/ogclient_mount
# Antes del montaje le cambiamos el nombre a la iso por un nombre generico
mv -f $OGLIVEFILE $DOWNLOADDIR/oglive.iso 2>/dev/null || { echo "{\"status\": \"error\", \"error\": \"Cannot rename $OGLIVEFILE to oglive.iso.\"}"; exit 1; }
OGLIVEFILE=$DOWNLOADDIR/oglive.iso
# TMPDIR=/tmp/oglive
mkdir -p $OGLIVEDIR $TMPDIR $TMPDIR_SQUASHFS
if [ ! -d "$OGLIVEDIR" ]; then
echo "{\"status\": \"error\", \"error\": \"Failed to create or access directory $OGLIVEDIR.\"}"
exit 1
fi
if [ ! -d "$TMPDIR" ]; then
echo "{\"status\": \"error\", \"error\": \"Failed to create or access directory $TMPDIR.\"}"
exit 1
fi
if [ ! -d "$TMPDIR_SQUASHFS" ]; then
echo "{\"status\": \"error\", \"error\": \"Failed to create or access directory $TMPDIR_SQUASHFS.\"}"
exit 1
fi
trap "umount $TMPDIR; rm -fr $TMPDIR" 1 2 3 6 9 15
# sudo mount -o loop,ro $OGLIVEFILE $TMPDIR >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"mount failed.\"}"; exit 1; }
# Asumimos que esta el montaje añadido al fstab
# La linea fstab es la siguiente: /opt/ogboot/lib/oglive.iso /tmp/opt/ogboot/lib/ogLive iso9660 loop,ro,user 0 0
mount $OGLIVEFILE >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"mount failed.\"}"; exit 1; }
cp -va $TMPDIR/ogclient/* $OGLIVEDIR >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"Cannot copy files to ogLive directory.\"}"; exit 1; }
chmod -R u+w $OGLIVEDIR || { echo "{\"status\": \"error\", \"error\": \"Failed to change permissions.\"}"; exit 1; }
umount $TMPDIR >/dev/null 2>&1
if [ ! -f $INFOFILE ]; then
rm -f $TFTPDIR/$DEFOGLIVE $TFTPDIR/$OGCLIENT
ln -vfs $(basename $OGLIVEDIR) $TFTPDIR/$DEFOGLIVE >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"Linking to $TFTPDIR/$DEFOGLIVE failed.\"}"; exit 1; }
ln -vfs $DEFOGLIVE $TFTPDIR/$OGCLIENT >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"Linking to $TFTPDIR/$OGCLIENT failed.\"}"; exit 1; }
fi
if [ -n "$SAMBAPASS" ]; then
#echo -ne "$SAMBAPASS\n$SAMBAPASS\n" | $OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"setsmbpass failed with SAMBAPASS.\"}"; exit 1; }
echo -ne "$SAMBAPASS\n$SAMBAPASS\n" | $OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" || { echo "{\"status\": \"error\", \"error\": \"setsmbpass failed with SAMBAPASS.\"}"; exit 1; }
else
$OPENGNSYS/bin/setsmbpass "$(basename $OGLIVEDIR)" || { echo "{\"status\": \"error\", \"error\": \"setsmbpass failed no SAMBAPASS.\"}"; exit 1; }
fi
find -L $OGLIVEDIR -type d -exec chmod 755 {} \; >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"chmod directories failed.\"}"; exit 1; }
find -L $OGLIVEDIR -type f -exec chmod 644 {} \; >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"chmod files failed.\"}"; exit 1; }
sudo chown -R :opengnsys $OGLIVEDIR >/dev/null 2>&1 || { echo "{\"status\": \"error\", \"error\": \"chown failed.\"}"; exit 1; }
OGSQFS=$OGLIVEDIR/ogclient.sqfs
trap "exit 0" SIGINT
TMPDIR=/tmp/oglive
if mountpoint -q "$TMPDIR"; then
echo "$TMPDIR ya está montado, desmontando primero..."
umount $TMPDIR >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: No se pudo desmontar $TMPDIR"
exit 1
fi
fi
echo "montando $TMPDIR_SQUASHFS"
if mount $TMPDIR_SQUASHFS ; then
RSYNCSERV=$(rsync --version 2>/dev/null | awk '/protocol/ {print $6}')
echo "RSYNCSERV (versión en el servidor): $RSYNCSERV"
#RSYNCCLNT=$(sudo chroot $TMPDIR /usr/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}')
RSYNCCLNT=$($TMPDIR_SQUASHFS/usr/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}')
echo "RSYNCCLNT (versión en el cliente montado): $RSYNCCLNT"
if [ -z "$RSYNCSERV" ] || [ "$RSYNCSERV" -gt "${RSYNCCLNT:-1}" ]; then
if [ -e "$OPENGNSYS/client/bin/rsync-$RSYNCSERV" ]; then
mv -f "$OPENGNSYS/client/bin/rsync-$RSYNCSERV" "$OPENGNSYS/client/bin/rsync" 2>/dev/null
fi
else
if [ -e "$OPENGNSYS/client/bin/rsync" ]; then
mv -f "$OPENGNSYS/client/bin/rsync" "$OPENGNSYS/client/bin/rsync-$($OPENGNSYS/client/bin/rsync --version 2>/dev/null | awk '/protocol/ {print $6}')"
fi
fi
umount $TMPDIR_SQUASHFS
rmdir $TMPDIR_SQUASHFS || sudo rm -rf $TMPDIR_SQUASHFS
fi
echo "finished mount squashfs"
# sudo rm -f "$OGLIVEFILE"
CHECKSUM_FILE="$OGLIVEDIR/ogclient.sqfs.sum"
if [ -f "$CHECKSUM_FILE" ]; then
OGLIVEID=$(cat "$CHECKSUM_FILE")
else
OGLIVEID="N/A" # Si no existe el archivo, asignamos un valor por defecto
fi
# Crear el archivo JSON con los datos del ogLive instalado
jq -n \
--arg OGLIVEDIST "$OGLIVEDIST" \
--arg OGLIVEKRNL "$OGLIVEKRNL" \
--arg OGLIVEARCH "$OGLIVEARCH" \
--arg OGLIVEREV "$OGLIVEREV" \
--arg OGLIVEDIR "$OGLIVEDIR" \
'{
OGLIVEDIST: $OGLIVEDIST,
OGLIVEKRNL: $OGLIVEKRNL,
OGLIVEARCH: $OGLIVEARCH,
OGLIVEREV: $OGLIVEREV,
OGLIVEDIR: $OGLIVEDIR
}' > "$OGLIVEDIR/oglive_info.json"
# Verificar que el archivo JSON fue creado
if [ ! -f "$OGLIVEDIR/oglive_info.json" ]; then
echo "{\"status\": \"error\", \"error\": \"oglive_info,json failed.\"}"; exit 1;
fi
JSON_OUTPUT=$(jq -n \
--arg id "$OGLIVEID" \
--arg dist "$OGLIVEDIST" \
--arg krnl "$OGLIVEKRNL" \
--arg arch "$OGLIVEARCH" \
--arg rev "$OGLIVEREV" \
--arg dir "$OGLIVEDIR" \
'{status: "success", message: {id: $id, distribution: $dist, kernel: $krnl, architecture: $arch, revision: $rev, directory: $dir}}')
echo "$JSON_OUTPUT"
}
# Uninstall an ogLive client.
function uninstall() {
local CHECKSUM DIR
# Validar que se proporcionó exactamente un argumento (el checksum)
[ $# -ne 1 ] && { echo "{\"error\": \"usage: uninstall {checksum}\"}"; exit 1; }
CHECKSUM=$1
# Verificar acceso a los directorios necesarios
[ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; }
# Buscar el directorio correspondiente al checksum
DIR=$(find $TFTPDIR -type f -name 'ogclient.sqfs.sum' -exec grep -l "$CHECKSUM" {} \; | xargs -I{} dirname {})
# Si no se encuentra el directorio, devolver error
if [ -z "$DIR" ]; then
echo "{\"error\": \"ogLive client with checksum $CHECKSUM not found.\"}"
exit 1
fi
# Eliminar archivos y directorio, redirigiendo la salida a /dev/null
rm -vfr $DIR > /dev/null 2>&1
# Comprobar si la eliminación tuvo éxito
if [ -d "$DIR" ]; then
echo "{\"error\": \"Failed to uninstall ogLive client in $DIR.\"}"
exit 1
fi
# Devolver mensaje de éxito
echo "{\"message\": \"ogLive client uninstalled successfully.\", \"details\": \"Removed directory: $DIR\"}"
}
# Get information about the default ogLive client.
function get_default() {
local DEFAULT_LINK="$TFTPDIR/$DEFOGLIVE"
local DIR OGLIVEJSON OGLIVEDIST OGLIVEKRNL OGLIVEARCH OGLIVEREV OGLIVEDIR CHECKSUM_FILE CHECKSUM
# Verificar que el enlace simbólico del ogLive por defecto existe.
if [ ! -L "$DEFAULT_LINK" ]; then
echo "{\"error\": \"Default ogLive client link not found.\"}"
exit 1
fi
# Obtener el directorio real al que apunta el enlace simbólico.
DIR=$(readlink -f "$DEFAULT_LINK")
# Si no se encuentra el directorio, devolver error.
if [ -z "$DIR" ]; then
echo "{\"error\": \"Default ogLive client directory not found.\"}"
exit 1
fi
# Verificar que el archivo oglive_info.json existe en el directorio.
OGLIVEJSON="$DIR/oglive_info.json"
if [ ! -f "$OGLIVEJSON" ]; then
echo "{\"error\": \"oglive_info.json not found in $DIR.\"}"
exit 1
fi
# Leer los datos del archivo JSON.
OGLIVEDIST=$(jq -r '.OGLIVEDIST' "$OGLIVEJSON")
OGLIVEKRNL=$(jq -r '.OGLIVEKRNL' "$OGLIVEJSON")
OGLIVEARCH=$(jq -r '.OGLIVEARCH' "$OGLIVEJSON")
OGLIVEREV=$(jq -r '.OGLIVEREV' "$OGLIVEJSON")
OGLIVEDIR=$(jq -r '.OGLIVEDIR' "$OGLIVEJSON")
# Obtener el checksum del archivo ogclient.sqfs.sum
CHECKSUM_FILE="$DIR/ogclient.sqfs.sum"
if [ -f "$CHECKSUM_FILE" ]; then
CHECKSUM=$(cat "$CHECKSUM_FILE" | cut -d ' ' -f 1)
else
CHECKSUM=""
fi
# Construir el JSON con la información.
local INFO=$(cat << EOT
{
"id": "$CHECKSUM",
"distribution": "$OGLIVEDIST",
"kernel": "$OGLIVEKRNL",
"architecture": "$OGLIVEARCH",
"revision": "$OGLIVEREV",
"directory": "$OGLIVEDIR"
}
EOT
)
# Devolver la información en formato JSON.
echo "$INFO"
}
# Set default ogLive client by checksum.
function set_default() {
local CHECKSUM=$1
local DIR
# Validar que se proporcionó exactamente un argumento (el checksum)
[ $# -ne 1 ] && { echo "{\"error\": \"usage: set-default {checksum}\"}"; exit 1; }
# Verificar acceso a los directorios necesarios
[ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; }
# Buscar el directorio correspondiente al checksum
DIR=$(find $TFTPDIR -type f -name 'ogclient.sqfs.sum' -exec grep -l "$CHECKSUM" {} \; | xargs -I{} dirname {} | grep -v ".old")
# Si no se encuentra el directorio, devolver error
if [ -z "$DIR" ]; then
echo "{\"error\": \"ogLive client with checksum $CHECKSUM not found.\"}"
exit 1
fi
# Eliminar el enlace simbólico existente y crear uno nuevo
rm -f $TFTPDIR/$DEFOGLIVE > /dev/null 2>&1
ln -vfs $(basename $DIR) $TFTPDIR/$DEFOGLIVE > /dev/null 2>&1
# Comprobar si el enlace simbólico se creó correctamente
if [ "$(readlink -f $TFTPDIR/$DEFOGLIVE)" == "$(readlink -f $DIR)" ]; then
echo "{\"message\": \"ogLive client set as default successfully.\", \"details\": \"$DIR\"}"
else
echo "{\"error\": \"Failed to set default ogLive client.\"}"
exit 1
fi
}
# Get disk usage information
function disk_usage() {
DISK_INFO=$(df -h / | awk 'NR==2{print "{\"total\":\""$2"\", \"used\":\""$3"\", \"available\":\""$4"\", \"percentage\":\""$5"\"}"}')
echo $DISK_INFO
}
# Function to list installed ogLive clients and the default ogLive client
function list_installed_oglives() {
local INST NF DEF
INST=$(find $TFTPDIR/ -type d -name "$DEFOGLIVE-*" -a ! -name "*.old" -printf "%f\n" | sort)
local installed_ogLives=()
for i in $INST; do
local OGLIVEDIR="$TFTPDIR/$i"
local OGLIVEDIST=""
local OGLIVEKRNL=""
local OGLIVEARCH=""
local OGLIVEREV=""
local CHECKSUM=""
local OGLIVEJSON="$OGLIVEDIR/oglive_info.json"
local CHECKSUM_FILE="$OGLIVEDIR/ogclient.sqfs.sum"
# Verificar que el archivo oglive_info.json existe en el directorio.
if [ -f "$OGLIVEJSON" ]; then
OGLIVEDIST=$(jq -r '.OGLIVEDIST' "$OGLIVEJSON")
OGLIVEKRNL=$(jq -r '.OGLIVEKRNL' "$OGLIVEJSON")
OGLIVEARCH=$(jq -r '.OGLIVEARCH' "$OGLIVEJSON")
OGLIVEREV=$(jq -r '.OGLIVEREV' "$OGLIVEJSON")
else
echo "{\"error\": \"oglive_info.json not found in $OGLIVEDIR.\"}"
continue
fi
# Obtener el checksum del archivo ogclient.sqfs.sum
if [ -f "$CHECKSUM_FILE" ]; then
CHECKSUM=$(cat "$CHECKSUM_FILE" | cut -d ' ' -f 1)
fi
# Crear el JSON con los datos del ogLive
local DATA=$(jq -n \
--arg id "$CHECKSUM" \
--arg dist "$OGLIVEDIST" \
--arg krnl "$OGLIVEKRNL" \
--arg arch "$OGLIVEARCH" \
--arg rev "$OGLIVEREV" \
--arg dir "$OGLIVEDIR" \
'{id: $id, distribution: $dist, kernel: $krnl, architecture: $arch, revision: $rev, directory: $dir}')
installed_ogLives+=("$DATA")
# Verificar si es el ogLive por defecto
[ -n "$(stat -c "%N" $TFTPDIR/$DEFOGLIVE | awk '$3~/'$i'/ {print}')" ] && DEF="$i"
done
local default_oglive=$(basename $(readlink -f $TFTPDIR/$DEFOGLIVE))
# Crear el JSON final con la lista de ogLives instalados y el ogLive por defecto
jq -n \
--arg default_oglive "$default_oglive" \
--argjson installed_ogLives "$(printf '%s\n' "${installed_ogLives[@]}" | jq -s .)" \
'{
default_oglive: $default_oglive,
installed_ogLives: $installed_ogLives
}'
}
# Get information about an installed ogLive client.
function get_info() {
local CHECKSUM="$1"
local DIR OGLIVEDIST OGLIVEKRNL OGLIVEARCH OGLIVEREV OGLIVEDIR OGLIVEJSON
# Verificar que se proporcionó un checksum.
[ -z "$CHECKSUM" ] && { echo "{\"error\": \"usage: get_info {checksum}\"}"; exit 1; }
# Verificar acceso al directorio de instalación.
[ ! -w $TFTPDIR ] && { echo "{\"error\": \"access installation directory.\"}"; exit 1; }
# Buscar el directorio correspondiente al checksum, excluyendo los que terminan en .old.
DIR=$(find $TFTPDIR -type f -name 'ogclient.sqfs.sum' -exec grep -l "$CHECKSUM" {} \; | grep -v '.old' | xargs -I{} dirname {})
# Si no se encuentra el directorio, devolver error.
if [ -z "$DIR" ]; then
echo "{\"error\": \"ogLive client with checksum $CHECKSUM not found.\"}"
exit 1
fi
# Verificar que el archivo oglive_info.json existe en el directorio.
OGLIVEJSON="$DIR/oglive_info.json"
if [ ! -f "$OGLIVEJSON" ]; then
echo "{\"error\": \"oglive_info.json not found in $DIR.\"}"
exit 1
fi
# Leer los datos del archivo JSON.
OGLIVEDIST=$(jq -r '.OGLIVEDIST' "$OGLIVEJSON")
OGLIVEKRNL=$(jq -r '.OGLIVEKRNL' "$OGLIVEJSON")
OGLIVEARCH=$(jq -r '.OGLIVEARCH' "$OGLIVEJSON")
OGLIVEREV=$(jq -r '.OGLIVEREV' "$OGLIVEJSON")
OGLIVEDIR=$(jq -r '.OGLIVEDIR' "$OGLIVEJSON")
# Construir el JSON con los datos del ogLive y el checksum (id).
local INFO=$(cat << EOT
{
"id": "$CHECKSUM",
"distribution": "$OGLIVEDIST",
"kernel": "$OGLIVEKRNL",
"architecture": "$OGLIVEARCH",
"revision": "$OGLIVEREV",
"directory": "$OGLIVEDIR"
}
EOT
)
# Devolver la información en formato JSON.
echo "$INFO"
}
# Function to check the status of services
function check_services_status() {
local SERVICES=("tftpd-hpa.service" "nginx.service")
declare -A STATUS_MAP
for service in "${SERVICES[@]}"; do
if systemctl list-units --type=service --all | grep -q "$service"; then
STATUS=$(systemctl is-active "$service")
STATUS_MAP[$service]=$STATUS
else
STATUS_MAP[$service]="not installed"
fi
done
local json_output=$(jq -n \
--arg oglive_daemon "${STATUS_MAP['oglive_daemon.service']}" \
--arg tftpboot "${STATUS_MAP['tftpd-hpa.service']}" \
--arg nginx "${STATUS_MAP['nginx.service']}" \
'{
oglive_daemon: $oglive_daemon,
tftpboot: $tftpboot,
nginx: $nginx
}')
echo "$json_output"
}
# Main program.
# Access control.
if [ "$USER" = "root" ] || [ "$USER" = "ogboot" ] || groups $USER | grep -qw "ogboot"; then
ACCESS="root"
else
raiseError access "Need to be root, ogboot or a member of the ogboot group."
fi
# Check dependencies.
which sponge &>/dev/null || raiseError notfound "Need to install \"moreutils\"."
# Commands control.
shopt -s extglob
CMDS='+(help|version|disk_usage|list_installed_oglives|check_services_status|download|install|uninstall|get_default|set_default|get_info)'
case "$1" in
$CMDS) COMMAND="${1/-/}"; shift; $COMMAND "$@" ;;
*) raiseError usage ;;
esac
exit $?