Exercicis Bash 05: systemd i Suport Gràfic

Preparatius

# Instal·lar zenity i notify-send
sudo apt install zenity libnotify-bin -y

# Crear directoris de treball
mkdir -p ~/practica_systemd/{scripts,services}
cd ~/practica_systemd

Exercici 1: Crear un servei systemd de monitorització (45 minuts)

Crea un servei que monitoritza l'ús de disc i CPU cada 30 segons i envia notificacions si superen un llindar.

Part A: Crear l'script de monitorització

Crea scripts/monitor_sistema.sh:

#!/bin/bash

##############################################
# Script de monitorització del sistema
##############################################

# Configuració
DISC_LIMIT=80      # Percentatge màxim de disc
CPU_LIMIT=75       # Percentatge màxim de CPU
LOG_FILE="/var/log/monitor_sistema.log"

# Funció de log
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# Funció per comprovar disc
comprovar_disc() {
    local us=$(df -h / | tail -1 | awk '{print $5}' | sed 's/%//')
    
    log "Disc: ${us}%"
    
    if [ $us -gt $DISC_LIMIT ]; then
        log "ALERTA: Disc supera el límit ($DISC_LIMIT%)"
        
        # Enviar notificació (només si hi ha display)
        if [ -n "$DISPLAY" ]; then
            notify-send -u critical \
                -i dialog-warning \
                "Alerta de Disc" \
                "El disc està al ${us}% (límit: ${DISC_LIMIT}%)"
        fi
        
        return 1
    fi
    
    return 0
}

# Funció per comprovar CPU
comprovar_cpu() {
    # Obtenir càrrega CPU (últim minut)
    local cpu=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
    local cpu_int=${cpu%.*}  # Convertir a enter
    
    log "CPU: ${cpu_int}%"
    
    if [ $cpu_int -gt $CPU_LIMIT ]; then
        log "ALERTA: CPU supera el límit ($CPU_LIMIT%)"
        
        if [ -n "$DISPLAY" ]; then
            notify-send -u critical \
                -i dialog-warning \
                "Alerta de CPU" \
                "La CPU està al ${cpu_int}% (límit: ${CPU_LIMIT}%)"
        fi
        
        return 1
    fi
    
    return 0
}

# Programa principal
log "=== Inici de monitorització ==="

while true; do
    comprovar_disc
    comprovar_cpu
    
    # Esperar 30 segons
    sleep 30
done

Part B: Crear el servei systemd

Crea /etc/systemd/system/monitor-sistema.service:

[Unit]
Description=Monitor del sistema (disc i CPU)
After=network.target

[Service]
Type=simple
ExecStart=/home/USUARI/practica_systemd/scripts/monitor_sistema.sh
Restart=always
RestartSec=10s
StandardOutput=journal
StandardError=journal

# Variables d'entorn per a notify-send (si s'executa en sessió gràfica)
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/USUARI/.Xauthority"

[Install]
WantedBy=multi-user.target

IMPORTANT: Substitueix USUARI pel teu nom d'usuari!

Tasques

  1. Crea l'script i fes-lo executable:

    chmod +x scripts/monitor_sistema.sh
    
  2. Crea el fitxer de servei (amb sudo i substitutint USUARI)

  3. Recarrega systemd:

    sudo systemctl daemon-reload
    
  4. Inicia el servei:

    sudo systemctl start monitor-sistema.service
    
  5. Comprova l'estat:

    systemctl status monitor-sistema.service
    
  6. Veure logs en temps real:

    journalctl -u monitor-sistema.service -f
    
  7. Comprova el fitxer de log:

    sudo tail -f /var/log/monitor_sistema.log
    
  8. Prova de generar càrrega per veure les alertes:

    # Generar càrrega CPU
    yes > /dev/null &
    # (Ctrl+C per aturar després)
    
  9. Habilita el servei per iniciar al boot:

    sudo systemctl enable monitor-sistema.service
    

Bonus

Modifica l'script per:


Exercici 2: Timer per backups automàtics (30 minuts)

Crea un timer systemd que faci backups automàtics cada dia.

Part A: Script de backup

Crea scripts/backup_automatitzat.sh:

#!/bin/bash

##############################################
# Script de backup automatitzat
##############################################

ORIGEN="/home/$USER/Documents"
DESTI="/home/$USER/Backups"
LOG="/var/log/backup_automatitzat.log"

# Crear directori de destinació
mkdir -p "$DESTI"

# Generar nom del backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
ARXIU="$DESTI/backup_$TIMESTAMP.tar.gz"

# Log
echo "[$(date)] Iniciant backup de $ORIGEN..." >> "$LOG"

# Crear backup
if tar -czf "$ARXIU" "$ORIGEN" 2>> "$LOG"; then
    MIDA=$(du -h "$ARXIU" | cut -f1)
    echo "[$(date)] Backup creat: $ARXIU ($MIDA)" >> "$LOG"
    
    # Notificació
    notify-send -i dialog-information \
        "Backup completat" \
        "S'ha creat el backup correctament ($MIDA)"
    
    # Neteja: eliminar backups més antics de 7 dies
    find "$DESTI" -name "backup_*.tar.gz" -mtime +7 -delete
    echo "[$(date)] Backups antics eliminats" >> "$LOG"
    
    exit 0
else
    echo "[$(date)] ERROR creant backup" >> "$LOG"
    
    notify-send -u critical -i dialog-error \
        "Error en backup" \
        "No s'ha pogut crear el backup"
    
    exit 1
fi

Part B: Crear servei i timer

Servei: /etc/systemd/system/backup-automatitzat.service

[Unit]
Description=Backup automatitzat de documents

[Service]
Type=oneshot
ExecStart=/home/USUARI/practica_systemd/scripts/backup_automatitzat.sh
User=USUARI
StandardOutput=journal
StandardError=journal

Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/USUARI/.Xauthority"

Timer: /etc/systemd/system/backup-automatitzat.timer

[Unit]
Description=Executar backup cada dia a les 20:00

[Timer]
OnCalendar=daily
OnCalendar=20:00
Persistent=true

[Install]
WantedBy=timers.target

Tasques

  1. Crea l'script i fes-lo executable

  2. Crea els fitxers de servei i timer (substitueix USUARI)

  3. Recarrega systemd:

    sudo systemctl daemon-reload
    
  4. Habilita i inicia el timer:

    sudo systemctl enable --now backup-automatitzat.timer
    
  5. Comprova l'estat del timer:

    systemctl status backup-automatitzat.timer
    systemctl list-timers
    
  6. Forçar execució immediata per provar:

    sudo systemctl start backup-automatitzat.service
    
  7. Veure logs:

    journalctl -u backup-automatitzat.service
    cat /var/log/backup_automatitzat.log
    

Variacions per provar

Modifica el timer per executar-se:


Exercici 3: Script amb interfície gràfica zenity (45 minuts)

Crea un script amb menú gràfic per gestionar backups.

Crear scripts/gestor_backups_gui.sh

#!/bin/bash

##############################################
# Gestor de Backups amb interfície gràfica
##############################################

DESTI_BACKUPS="$HOME/Backups"
mkdir -p "$DESTI_BACKUPS"

# Funcions per diàlegs
mostrar_info() {
    zenity --info --title="Gestor de Backups" --text="$1" --width=300
}

mostrar_error() {
    zenity --error --title="Error" --text="$1" --width=300
}

preguntar() {
    zenity --question --title="Confirmació" --text="$1" --width=300
}

# Funció: Fer backup
fer_backup() {
    # Seleccionar directori origen
    ORIGEN=$(zenity --file-selection --directory \
        --title="Selecciona directori per fer backup")
    
    if [ -z "$ORIGEN" ]; then
        mostrar_error "No s'ha seleccionat cap directori"
        return 1
    fi
    
    # Confirmar
    if ! preguntar "Fer backup de:\n$ORIGEN\n\nDestí:\n$DESTI_BACKUPS"; then
        return 0
    fi
    
    # Generar nom
    NOM_DIR=$(basename "$ORIGEN")
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    ARXIU="$DESTI_BACKUPS/backup_${NOM_DIR}_${TIMESTAMP}.tar.gz"
    
    # Crear backup amb barra de progrés
    (
        echo "10" ; echo "# Preparant backup..."
        sleep 1
        
        echo "30" ; echo "# Comprimint fitxers..."
        tar -czf "$ARXIU" "$ORIGEN" 2>&1 | \
            while read linia; do
                echo "# $linia"
            done
        
        echo "80" ; echo "# Verificant integritat..."
        sleep 1
        
        if tar -tzf "$ARXIU" > /dev/null 2>&1; then
            echo "100" ; echo "# Completat!"
        else
            echo "100" ; echo "# Error de verificació"
        fi
    ) | zenity --progress \
        --title="Creant backup" \
        --text="Iniciant..." \
        --percentage=0 \
        --auto-close \
        --width=400
    
    # Comprovar resultat
    if [ -f "$ARXIU" ]; then
        MIDA=$(du -h "$ARXIU" | cut -f1)
        notify-send -i dialog-information \
            "Backup completat" \
            "Arxiu: $(basename "$ARXIU")\nMida: $MIDA"
        
        mostrar_info "Backup creat correctament!\n\nArxiu: $(basename "$ARXIU")\nMida: $MIDA"
    else
        notify-send -u critical -i dialog-error \
            "Error en backup" \
            "No s'ha pogut crear el backup"
        
        mostrar_error "Error creant el backup"
    fi
}

# Funció: Llistar backups
llistar_backups() {
    if [ ! "$(ls -A $DESTI_BACKUPS/*.tar.gz 2>/dev/null)" ]; then
        mostrar_info "No hi ha backups disponibles"
        return 0
    fi
    
    # Preparar dades per a la llista
    DADES=""
    for backup in "$DESTI_BACKUPS"/*.tar.gz; do
        NOM=$(basename "$backup")
        MIDA=$(du -h "$backup" | cut -f1)
        DATA=$(stat -c %y "$backup" | cut -d. -f1)
        DADES+="FALSE\n$NOM\n$MIDA\n$DATA\n"
    done
    
    # Mostrar llista amb checkbox
    SELECCIONAT=$(echo -e "$DADES" | zenity --list \
        --title="Backups disponibles" \
        --text="Selecciona un backup:" \
        --checklist \
        --column="Sel" --column="Nom" --column="Mida" --column="Data" \
        --width=700 --height=400 \
        --separator="|")
    
    if [ -n "$SELECCIONAT" ]; then
        # Demanar què fer amb el backup seleccionat
        ACCIO=$(zenity --list \
            --title="Acció" \
            --text="Què vols fer amb '$SELECCIONAT'?" \
            --column="Acció" \
            "Veure contingut" \
            "Restaurar" \
            "Eliminar" \
            --width=300 --height=250)
        
        case "$ACCIO" in
            "Veure contingut")
                veure_contingut "$DESTI_BACKUPS/$SELECCIONAT"
                ;;
            "Restaurar")
                restaurar_backup "$DESTI_BACKUPS/$SELECCIONAT"
                ;;
            "Eliminar")
                eliminar_backup "$DESTI_BACKUPS/$SELECCIONAT"
                ;;
        esac
    fi
}

# Funció: Veure contingut d'un backup
veure_contingut() {
    local arxiu=$1
    
    # Llistar contingut
    CONTINGUT=$(tar -tzf "$arxiu" 2>&1)
    
    if [ $? -eq 0 ]; then
        echo "$CONTINGUT" | zenity --text-info \
            --title="Contingut de $(basename "$arxiu")" \
            --width=600 --height=400
    else
        mostrar_error "Error llegint el backup"
    fi
}

# Funció: Restaurar backup
restaurar_backup() {
    local arxiu=$1
    
    # Seleccionar directori de restauració
    DESTI_RESTAURACIO=$(zenity --file-selection --directory \
        --title="On vols restaurar el backup?")
    
    if [ -z "$DESTI_RESTAURACIO" ]; then
        return 0
    fi
    
    if ! preguntar "Restaurar $(basename "$arxiu") a:\n$DESTI_RESTAURACIO"; then
        return 0
    fi
    
    # Restaurar amb barra de progrés
    (
        echo "50" ; echo "# Extraient fitxers..."
        tar -xzf "$arxiu" -C "$DESTI_RESTAURACIO" 2>&1
        echo "100" ; echo "# Completat!"
    ) | zenity --progress \
        --title="Restaurant backup" \
        --percentage=0 \
        --auto-close \
        --width=400
    
    if [ $? -eq 0 ]; then
        notify-send -i dialog-information \
            "Restauració completada" \
            "Backup restaurat a: $DESTI_RESTAURACIO"
        
        mostrar_info "Backup restaurat correctament!"
    else
        mostrar_error "Error restaurant el backup"
    fi
}

# Funció: Eliminar backup
eliminar_backup() {
    local arxiu=$1
    
    if preguntar "Segur que vols eliminar:\n$(basename "$arxiu")?"; then
        rm -f "$arxiu"
        
        if [ $? -eq 0 ]; then
            notify-send -i dialog-information \
                "Backup eliminat" \
                "$(basename "$arxiu") ha estat eliminat"
            
            mostrar_info "Backup eliminat correctament"
        else
            mostrar_error "Error eliminant el backup"
        fi
    fi
}

# Funció: Configuració
configuracio() {
    DADES=$(zenity --forms \
        --title="Configuració" \
        --text="Paràmetres del sistema" \
        --add-entry="Directori de backups" \
        --add-entry="Temps de retenció (dies)" \
        --add-combo="Compressió" \
        --combo-values="gzip|bzip2|xz")
    
    if [ -n "$DADES" ]; then
        mostrar_info "Configuració actualitzada!\n\n$DADES"
    fi
}

# Menú principal
while true; do
    OPCIO=$(zenity --list \
        --title="Gestor de Backups" \
        --text="Selecciona una opció:" \
        --column="Acció" \
        --column="Descripció" \
        --width=500 --height=350 \
        "backup" "Crear nou backup" \
        "llistar" "Veure backups disponibles" \
        "config" "Configuració" \
        "info" "Informació del sistema" \
        "sortir" "Sortir")
    
    case "$OPCIO" in
        backup)
            fer_backup
            ;;
        llistar)
            llistar_backups
            ;;
        config)
            configuracio
            ;;
        info)
            INFO="Sistema: $(uname -s)\n"
            INFO+="Hostname: $(hostname)\n"
            INFO+="Usuari: $USER\n"
            INFO+="Directori backups: $DESTI_BACKUPS\n"
            INFO+="Backups totals: $(ls "$DESTI_BACKUPS"/*.tar.gz 2>/dev/null | wc -l)\n"
            INFO+="Espai ocupat: $(du -sh "$DESTI_BACKUPS" 2>/dev/null | cut -f1)"
            
            zenity --info --title="Informació del sistema" \
                --text="$INFO" --width=400
            ;;
        sortir|"")
            if preguntar "Segur que vols sortir?"; then
                exit 0
            fi
            ;;
    esac
done

Tasques

  1. Crea l'script i fes-lo executable

  2. Executa'l:

    ./scripts/gestor_backups_gui.sh
    
  3. Prova totes les funcions:

    • Crear un backup
    • Llistar backups
    • Veure contingut
    • Restaurar
    • Eliminar
  4. Crea una entrada al menú d'aplicacions:

    mkdir -p ~/.local/share/applications
    cat > ~/.local/share/applications/gestor-backups.desktop << EOF
    [Desktop Entry]
    Version=1.0
    Type=Application
    Name=Gestor de Backups
    Comment=Gestionar backups del sistema
    Exec=$HOME/practica_systemd/scripts/gestor_backups_gui.sh
    Icon=drive-harddisk
    Terminal=false
    Categories=Utility;
    EOF
    

Exercici extra: Integració completa

Crea un sistema complet que:

  1. Servei systemd de monitorització contínua
  2. Timer per backups automàtics
  3. Script GUI per gestionar-ho tot manualment

Afegeix:


Criteris d'avaluació