martedì 21 gennaio 2014

Un posto lontano e tranquillo

Servizi e Cotillon

Oggi un sacco di gente gira con sti cosi rettangolari, che chiamano Tablet o anche Smartphones . Gente affamata di servizi online nuovissimi e di incredibile utilità, come la mail e lo spazio di storage.

Ricordo che la prima volta che mi presentarono Dropbox rimasi un quarto d'ora a cercare di capirne l'utilità. Cosa aveva questo servizio in più, di un server remoto dove mettere i miei files ? Soprattutto cosa aveva in meno ?

So che sono domande che uno non dovrebbe porsi, perché non sono più di moda e infatti dopo un po`di tempo, ecco apparire Google Drive, che ha fugato ogni dubbio.

Devo dire che ognuno dei due servizi ha proprie caratteristiche : entrambi offrono la sincronizzazione con un proprio protocollo proprietario, ma Google Drive, ha la tendenza a privilegiare, senza sorpresa, il lavoro puramente online.

Entrambi offrono uno spazio gratuito limitato, entrambi si impadroniscono del vostro tablet e telefono e se non ci state attenti, incominciano a copiare le vostre foto e i vostri documenti in remoto (assumendo che è quello che ovviamente volete).

Poi nel caso di Google Drive queste foto sono analizzate e indicizzate, in modo che se fate la scansione di una ricevuta, potete anche cercarla direttamente, perché è sicuramente questo quello che volete.

Con questo non voglio scoraggiarvi anzi vi invito, prima di cliccare su "Accetto", di leggervi anche le policy sulla privacy, così vi fate un quadro completo.

Se volete divertirvi c'è anche gente su Internet che consiglia di metterci le fotocopie dei documenti e della carta di credito, io vi consiglio anche di usare G+ e una password tipo 12345 che pare vada per la maggiore di questi tempi.

E se voglio farlo da me ?

Se volete farlo da voi, con Linux ci sono 3 cose di cui avete bisogno e senza le quali è difficile combinare qualcosa :

  • L'accesso al router ADSL per abilitare i virtual server.
  • Un serverino locale sempre acceso.
  • L'iscrizione a un servizio Dynamic DNS, se avete l'IP dinamico, se avete l'IP statico il Dynamic DNS non serve, basta l'indirizzo.

Oggi, la maggior parte di quelli che si collegano ad Internet, hanno a casa un routerino, che di solito permette anche l'accesso alle impostazioni di base.

L'iscrizione al Dynamic DNS è generalmente gratuita. Io consiglio questo che è : comodissimo, leggero, non richiede un programma apposta ed e fatto proprio per girare sul server Linux, dove c'è il vostro serizio di storage.

Pochi hanno a casa un computer sempre acceso, però ci sono oggettini come il Raspberry PI , che si possono sempre mettere da qualche parte con il loro bel IP fisso, la loro schedina interna da 8 Giga con su Debian (di solito più di quanto c'è sul telefono), con una o due chiavettine USB esterne da 32 giga per esempio.

Io ne ho messa una sola perché all'altra ho attaccato una stampante, facendola diventare una stampante di rete.

Ovviamente il mio Raspberry è pieno di altri servizi, compreso un Server Web con cui controllo una serie di Intranet of things, ma questo non è oggetto della corrente discussione.

L'oggetto della corrente discussione, è il servizio o server che andrebbe attivato per garantire un sistema comodo e sicuro.

FTP, SFTP, FTPS o ...

Il servizio che è sempre stato usato per trasferire i files da un computer all'altro si chiama "servizio di trasferimento files" o FTP.

FTP è sempre stato un protocollo molto "disinvolto" : il client apre una socket sulla porta 21 si autentica, rigorosamente in chiaro,= e comincia a fare richieste di liste e files al server, che addirittura dovrebbe rispondergli aprendo lui (il server) una socket verso il client, senza per altro chiedersi cosa ne pensa il NAT di tutto questo.

Altri tempi, subito aggirati con l'introduzione del protocollo passivo, che almeno inverte questo meccanismo e poi da un sacco di altre piccole cose, come i comandi estesi.

Quando hanno visto che tutto ciò non era abbastanza, perché le password e i dati passavano ancora in chiaro, hanno pensato di usare l'autenticazione TLS ed eventualmente di incapsulare il tutto in un bel tunnel SSL .

Il risultato finale è stato FTPS che è un ottimo protocollo, anche se richiede parecchio lavoro dal punto di vista della configurazione, compresa l'autenticazione di chiavi (che possono anche essere "self signed").

Dall'altra parte della barricata, si sono accorti che anche il sistema di accesso dei sistemi POSIX aveva seri problemi di sicurezza, visto che anche lì passava tutto in chiaro, allora hanno pensato a fare il passaggio inverso, cioè creare una specie di tunnel universale SSL, con varie possibilità di autenticazione e di farci passare dentro vari protocolli, tra i quali la classica shell , che hanno chiamato SSH.

Insieme alla shell, arrivano almeno SCP e SFTP.  Il primo è un comodo sistema di trasferimento rapido dei files tra macchine diverse, cioè la versione sicura di RCP ; il secondo non è FTP e non ha molto a che vedere con FTP , però è un protocollo binario, indipendente, piuttosto semplice da usare ed estremamente versatile.

Per tornare al RaspberryPI , SSH è già attivo e serve per accedervi da remoto.

Allo scopo di evitare problemi di installazione dei vari server FTP con tanto di chiavi e finte CA, ho scelto di semplificare le cose usando proprio SFTP.

Configurazione

La configurazione del server SSH o meglio del daemon sshd di solito è già li pronta per collegarsi. Ci si aggancia alla porta 22 e si comincia a ballare, permettendoci ogni forma di nefandezza, compreso l'accesso di root. Tanto è sicuro ...

Noi vogliamo come al solito strafare e scegliamo una alternativa.

Prima di tutto vogliamo avere due daemon sshd : uno interno alla nostra rete con il quale compiere le solite nefandezze e uno accessibile dall'esterno, con un solo utente e privilegi limitati.

Per far questo creiamo un utente che chiamiamo per esempio aristide, e gli affidiamo una password complicata di una decina di caratteri almeno, con maiuscole, minuscole e numeri, il tutto ovviamente da root.

# adduser aristide

Dobbiamo anche impedire al nostro amico aristide di collegarsi in login e questo lo facciamo da passwd, cioè :

# vi /etc/passwd

....
aristide:x:1001:1002:,,,:/home/aristide:/bin/false

e con lo user è stato creato anche un gruppo aristide di default.
Fatto questo andiamo in /etc/ssh e copiamo sshd_config in sshd_config_alt .

# cd /etc/ssh
# cp sshd_config sshd_config_alt

mi raccomando di ricordarvi la d perché l'altra è la configurazione del client.

A questo punto possiamo sentirci liberi di editare il file sshd_config_alt :

# vi sshd_config_alt

Qui parto da quello del Raspberry PI  e evidenzio le modifiche :

# Package generated configuration file
# See the sshd_config(5) manpage for details

# What ports, IPs and protocols we listen for

#Port 22 
Port 9345
# Use these options to restrict which interfaces/protocols sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes

# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 768

# Logging
SyslogFacility AUTH
LogLevel INFO

# Authentication:
LoginGraceTime 120
PermitRootLogin yes
StrictModes yes

RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile    %h/.ssh/authorized_keys

# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes

# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no

# Change to no to disable tunnelled clear text passwords
#PasswordAuthentication yes

# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

#X11Forwarding yes
#X11DisplayOffset 10
 
X11Forwarding no
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no

#MaxStartups 10:30:60
#Banner /etc/issue.net

# Allow client to pass locale environment variables
AcceptEnv LANG LC_*

#Subsystem sftp /usr/lib/openssh/sftp-server

Subsystem sftp internal-sftp
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes


AllowUsers aristide
AllowTcpForwarding no
ForceCommand internal-sftp
ChrootDirectory /storage


Quello che abbiamo fatto è :
  1. Cambiare la porta su una porta sconosciuta, per esempio la 9345.
  2. Limitare l'accesso al solo utente aristide, che non ha la possibilità di loggarsi ma solo di eseguire le operazioni di trasferimento files.
  3. Disabilitare ogni forma di forwarding conosciuto.
  4. Eseguire un chroot nella cartella /storage per impedire l'accesso al resto del disco.
Però non abbiamo finito, ora dobbiamo anche creare lo spazio di lavoro.

Andiamo in /storage e creiamo la cartella disk, poi mettiamo a posto i permessi in questo modo :

# mkdir /storage
# mkdir /storage/disk
# chown root:root /storage
# chown aristide:aristide /storage/disk

i permessi dovrebbero essere di entrambe le cartelle 755 cioè rwxr-xr-x, se non lo sono impostatele di conseguenza.

Il motivo per cui è stata creata la cartella /storage usabile solo da root, è un motivo di sicurezza, se non fate così sshd si arrabbia e vi impedisce di loggarvi.

D'altra parte in una cartella simile, aristide non può scrivere, quindi predisponiamo una cartella leggibile e scrivibile da aristide.

Ora si può creare uno script di partenza o modificare rc.local , per inserirci la chiamata al programma , una cosa del genere :

# /usr/sbin/sshd -f /etc/ssh/sshd_config_alt

e parte immediatamente un secondo daemon fatto su misura per noi.

Per collegarsi, si può provare da un altro computer con un semplice :

sftp -P 9345 aristide@<ip del computer>

inserire la password e ci si dovrebbe trovare nella root di storage, dove ovviamente non si può scrivere, ma entrando in disk potremo fare quello che vogliamo.

Una chiavetta per lo storage

Come ho detto, uso un RaspberryPI per fare tutto ciò e uso una chiavetta esterna come spazio di storage.

È molto interessante perché la chiavetta, a differenza del disco classico, non gira e non si usura, quando non ci scrivete e questo tipo di micro server, sono ideali per funzionare proprio con una chiavetta.

Il problema è come montarla. Qui avete due alternative :
  • o la formattate etx2 e predisponete un fsck.ext2 -p  prima di montarla.
  • o la mantenete formattata FAT e modificate le opzioni di mount opportunamente.
Se usate un ext2 potete fare un mount in questo modo :

mount /dev/sda1 -o noatime,nosuid,nodev,rw /storage/disk/

Se usate la classica chiavetta con FAT senza riformattarla dovete aggiungere i parametri per i permessi :

mount /dev/sda1 -o \
noatime,nosuid,nodev,rw,uid=1001,gid=1002,fmask=137,dmask=027 /storage/disk/

impedendo così l'esecuzione dei programmi e permettendo l'accesso e la visione solo a root, con un controllo completo da parte dell'utente.

Ovviamente i numerini sono gli stessi che avete visto prima in passwd e relativi all'utente aristide.

Accedere da remoto

Per permettere di entrare sul serverino da remoto, ipotizzando che la nostra rete abbia un classico 192.168.1.0/24 , e che l'IP fisso del server sia 192.168.1.50, possiamo andare nella configurazione di rete del nostro router e aprire quella che si chiama virtual server.

Io lo faccio sul mio router che è un cosettino di una certa marca, fornito dal provider.


E quindi impostare una porta così :


poi andare da uno delle decine di Dynamic DNS che ci sono in giro, iscrivervi, sceglievi un nome e fargli puntare al vostro IP.

E ora che si fa ?

In Linux con nautilus per esempio, potete fare Ctrl-l e inserire nella barra del File Manager :

sftp://aristide@<ip>:9345/disk

per esempio dalla vostra lan :



Da remoto dovete metterci l'indirizzo IP fisso o il vostro indirizzo Internet virtuale se usate un Dynamic DNS .

Da Windows potete usare svariati client, il più famoso è il WinSCP .

Su Android c'è AndFTP che è un po` grezzo, dal punto di vista della grafica (specie se avete un tablet da 10 pollici), ma vi permette di caricare ciò che vi interessa o scaricarlo in una cartella predisposta, in modo che poi sia accessibile da un qualsiasi file manager, lo impostate così :



Potete per esempio prendere le vostre foto del telefono, nella cartella DCIM , selezionarle e copiarle nella cartella remota, poi con il tablet potete scaricarle in shared e vederle, oppure col PC potete caricare un FILM , e metterlo nella cartella, per poi scaricarlo nuovamente.

Insomma potete fare ciò che volete, l'unica nota dolente è che se usate come me un RaspberryPI con una chiavetta, l'upload è molto lento, anche in locale, mentre il download è sensibilmetne più veloce.


domenica 12 gennaio 2014

Gnome Shell e le Cartelle Colorate





Dalle mie parti, si narra una antica leggenda per cui un mio lontano prozio, dopo vent'anni di lavoro in un disordinato ufficio, fu il primo e unico vero inventore delle cartellette colorate.

Non penso che questa leggenda sia vera, e non ho mai apprezzato il monumento che il sindaco volle dedicare al mio prozio, ma qualche volta, quando gironzolo per il disco del mio portatile, mi intristisco di fronte alla visione di tante cartellette tutte uguali e tutte dello stesso colore.

Una volta succedeva anche coi files, ma adesso i sistemi sono praticamente tutti dotati di un comodo sistema, per ottenere delle stupende thunbnails.

Per le cartelle però questo non succede, c'è stato qualche timido tentativo, specialmente con KDE, ma il grosso della questione è ancora irrisolto.

È facile capire il perché:  tranne alcuni casi, come le foto o la musica, il sistema non sà cosa c'è in una cartella e se cerca di prendere qualche preview per rappresentarla, magari l'immagine non è significativa e rischia solo di creare confusione.

Ok, quindi il sistema non lo sa, ma noi si.

Per esempio nel mio caso, quando sono lanciato in un lavoro, riempio le scrivanie, sia quella reale che quella virtuale, di documenti vari, poi : la prima la ordino butto un po`di cose nel cestino e metto il rimanente in un armadio e per la seconda faccio esattamente la stessa cosa, mettendo le cose in un armadio chiamato Folders della mia HOME utente.

Così come leggenda narra, che il mio prozio, steso sulla comoda poltrona dell'ufficio e guardando il grigiore di quell'armadio, pensò alle cartellette colorate, realtà vuole che guardando quel maledetto Folders pieno di cartellette tutte uguali, il sottoscritto abbia voluto per forza fare qualcosa.

Una iconcina a testa

La prima cosa è cercare delle immagini piccole che rappresentino le singole attività.

Fare questo è facile facile, basta andare su Google Images, scegliere l'apposita voce di ricerca Clip art , inserire il nome della cartella (o qualcosa di simile), per esempio Android e si trova sempre un modo per descriverla, per esempio questo coso :



Possiamo scegliere jpg o png, altri formati sono accettati ma è meglio stare sul classico.

Se avete scelto la ricerca Clip Art, l'iconcina sarà di pochi pixel e se è troppo grande potete ridimensionarla con cura per farla diventare qualcosa attorno ai 256 pixel, ma le dimensioni esatte non sono molto importanti.

A questo punto salvatela nel folder Folders/Android, col nome .icon .

In sintesi le vostre icone saranno files nascosti all'interno del folder stesso con nome .icon e senza estensione, perché come dovreste ben sapere, Linux non si basa sulle estensioni ma sui magic numbers, per riconoscere il formato.

E chi glielo spiega a Gnome Shell ?

Ora che in ogni subfolder del folder "Folders", c'è una icon nascosta di nome ".icon" chi glielo spiega a Gnome Shell ?

Può spiegarglielo l'interfaccia grafica, tasto destro, proprietà, si clicca sull'iconcina e si sceglie.

Però è noioso e come al solito noi cerchiamo qualcosa di più semplice da farsi, con l'immancabile script di poche righe.

Le iconcine sono associate agli attributi del Virtual File System di Gnome, quindi cosa ci può essere di più comodo del comando : gvfs-set-attribute ?

Si può scrivere :

gvfs-set-attribute -t string "<path assoluto del folder>" metadata::custom-icon "file:<path assoluto dell'immagine>"

dove il significato di path assoluto del folder e path assoluto dell'immagine lo lascio intuire a voi.


Il solito script

Si và nella propria cartella Folders o in qualsiasi altra grigissima cartella della vostra HOME, dalla Documents alla Workspace alla Development eccetera e si lancia il solito script che abbiamo chiamato seticons, il quale sta nella classica /usr/local/bin, salvato come root ed accessibile in lettura ed esecuzione  da tutti (chmod 755) e il gioco è fatto !

Cosa manca ? Lo Script . Quindi eccolo qui :

#!/bin/bash
p=`pwd`
for i in *
do
  if [ -d "$i" ]
  then
    if [ -r "$i/.icon" ]
    then
      gvfs-set-attribute -t string "$p/$i" metadata::custom-icon "file://$p/$i/.icon"
    fi
  fi
done


Questo mette in p il path da cui lo lanciamo, quindi nel mio caso immaginiamo : /home/duraminga/Folders, ricerca tutti gli elementi che ci sono nella cartella, e quando trova un subfolder ( -d "$i" ) , si avventura cercando l'eventuale presenza di un file nascosto .icon ( -r "$i/.icon" ) e se lo trova allora esegue il set che nel caso del subfolder Android è :

gvfs-set-attribute -t string "/home/duraminga/Folders/Android" metadata:custom-icon "file:///home/duraminga/Folders/Android/.icon"

combinazione, proprio quello che ci serve per impostare le iconcine, quindi apriamo Folders, et voilà :



Se lo ingrandiamo un pochino possiamo anche vedere il dettaglio del numero di elementi nelle cartelle, con grande soddisfazione del mio prozio.


lunedì 30 dicembre 2013

Sfondi di BING su Gnome Shell



 

(Scripta Manent IV)

BING e i suoi sfondi 

Bing, come quasi tutti sanno, è il motore di ricerca di casa Microsoft.

Per motivi personali, di recente ho voluto provare questo mondo alternativo di servizi, la cui qualità non vuole essere oggetto di questo eloquio.

Una cosa che però indubbiamente colpisce di BING è la bellezza dei suoi sfondi, che cambiano quotidianamente e che sembrano presi da un vastissimo pool di immagini di alta qualità.

Probabilmente l'usabilità di tali sfondi è vincolata da quintali di clausule e copyright, quindi dovrebbero essere prudenzialmente usati solo in sede alle pagine di Bing, ma pare anche come sfondi per l'ultima versione del loro sistema operativo.

D'altra parte non se la prenderà la grande M, se motivato da fervente ammirazione e dalle quattro pagine di questo blog autarchico, nell'intenzione di far capire ciò che si può fare con power sh... ehm con bash , suggerirò un piccolo script per cambiare di conseguenza gli sfondi di Gnome Shell .

Passo dopo passo

Per essere certo che la procedura sia valida anche in futuro e anche, perché no, per altre pagine e altri sfondi a venire, spiegherò passo dopo passo "come lo feci".

Come lo feci

Prima di tutto ci serve un sistema per interrogare il sito di Bing, nell'intenzione di capire se lo sfondo è cambiato.

Un uomo di poche parole, si accontenterebbe di una voce in crontab o di un semplice sleep, ma i più arditi sapranno che ormai ben pochi spengono i laptop o i netbook e la maggior parte usano il comodissimo "suspend".

E qui casca lo sleep, nel senso che se mettiamo uno sleep, questo si sospende per un certo tempo, poi si sospende la sospensione quando il computer è sospeso, e alla fine riprende la sospensione, così che ogni sleep dura da T a infinito, e noi non vogliamo che questo accada, vero ?

Se trasformiamo lo script in un daemon di sistema,  non dobbiamo preoccuparci di farlo partire o finire, ci basterà fidarci, quindi scriviamo qualche riga :




#!/bin/bash
OLDTIME=0
 

{
while true
do

  # Ten minutes ...
  /bin/sleep 600

 
  NEWTIME=`date +%s`

  # Try to download after 12 hours only
  if [ $(($NEWTIME-$OLDTIME)) -ge 43200 ]
  then

    OLDTIME=$NEWTIME

    # Place your code here 
    # ..... fi
   
done
} &


Se lanciamo questo script da sh, magari all'interno di rc.local, lui per prima cosa va in background e diventa un daemon, figlio di 1 cioè di init e inizia un infinito loop ad intervalli di 10 minuti.

In questo loop, si legge il valore +%s di date, cioè il numero di secondi assoluti da EPOCH ([GMT]1/1/1970:00:00:00) e si compara, all'inizio con 0 e poi con i valori letti di volta in volta.

Un sistema di questo tipo, ogni 10 minuti circa, a partire dal primo loop, verificherà la scadenza di 12 ore ed eseguirà il codice in mezzo.

Notate bene che al massimo sarà sospeso lo sleep di 10 minuti. Il motivo per cui ne faccio eseguire uno all'inizio e non alla fine del primo loop, è perché il computer appena acceso, se è connesso col Wi-Fi, di solito non è ancora in rete e la rete ci servirà sicuramente per quello che stiamo per fare.

Quello che stiamo per fare è questo :

       ...   
    # Get the bing home page and search for g_img tag
    page=`/usr/bin/curl --user-agent "$USERAGENT" www.bing.com | /bin/grep g_img`
    # Get the token after g_img
    page=${page##*g_img=}
    # Check the url argument
    page=${page#*url:\'}
    # Extract the url until '
    page=${page%%\'*}

    /usr/bin/curl --user-agent "$USERAGENT" "http://www.bing.com/$page" > $FOLDER/current_background.jpg

    ...

Per capirlo bene, dobbiamo innanzi tutto precisare che per il momento Bing fornisce una pagina con codice javascript, che a sua volta contiene degli oggetti json. Un oggetto json si chiama g_img e contiene alcuni attributi, tra i quali il classico url, ossia una stringa json tra apici semplici.

La prima riga legge la pagina da www.bing.com, ed estrae il blocco contenente g_img e lo mette in una semplice variabile di memoria, chiamata page.

Il risultato sarà parecchio garbage con il nucleo di quello che ci interessa, cioè :

... g_img={url:'az/hprichbg/rb/immagine.jpg';id...

Ecco quindi gli abili colpi di bash, per pulire un po` il contenuto :

page=${page##*g_img=}
page=${page#*url:\'} 
page=${page%%\'*}

e che si traducono in :
  1. prendi tutto ciò che c'è dopo g_img= 
  2. di questo prendi solo quello che c'è subito dopo la prima parola url:' e qui notate che ho usato un solo #, cioè il minimo match dell'espressione regolare (il massimo porterebbe in fondo al file)
  3. di quello che hai ottenuto scarta tutto quello che trovi dal primo ' fino alla fine.
Se ci pensate un po` su capite che ora in page abbiamo qualcosa tipo :

az/hprichbg/rb/immagine.jpg

dove al posto di immagine, c'è uno bel URL col nome e la risoluzione dell'immagine stessa, basta accodarlo a al sito originale e lanciare il curl quindi su :

http://it.bing.com/az/hprichbg/rb/immagine.jpg

che scaricherà l'URL in standard output, da noi rediretto in un fantomatico :

$FOLDER/current_background.jpg

Gnome Shell e il suo sfondo

L'immagine di sfondo di Gnome Shell, punta solitamente ad una jpeg specifica.

Nonostante l'immagine sia naturalmente su disco da qualche parte, essa è considerata dinamica, cioè appena la si cambia, Gnome Shell se ne accorge e cambia lo sfondo di conseguenza, con un gradevole effetto fade-out,fade-in.

Per noi la situazione è perfetta, infatti se pensiamo di usare quello che abbiamo appena scritto come daemon di sistema, lanciato da rc.local, in modo che ne possano usufruire tutti gli utenti, possiamo riservarci un posto d'onore per esempio nella /opt , qualcosa tipo /opt/background e lì metterci la current_background.jpg.

Per far questo, presa una qualsiasi genericaimmagine.jpg, si può eseguire da su, cioè da utente root, la seguente operazione :

# mkdir /opt/background
# cp genericaimmagine.jpg /opt/background/current_background.jpg

Ora non ci resta che indicare in /opt/background/current_background.jpg, l'immagine di sfondo corrente e questo lo dobbiamo fare come utente "normale" per esempio usando Nautilus nella cartella /opt/background e cliccare aprendola col normale Image Viewer, dove col menù popup (tasto destro) troviamo una opzione per usare tale immagine come sfondo :



Quando lo script, agirà, sovrascriverà l'immagine e il gioco sarà fatto.

Mettiamo insieme tutto

A questo punto approntiamo lo script completo, che è questo :


#!/bin/bash
# Bing Image Downloader
 

{
 

export OLDTIME=0
export FOLDER=/opt/background

export USERAGENT="Mozilla/5.0"

while true
do
  # Ten minutes loop
  /bin/sleep 600

  export NEWTIME=`date +%s`

  # Try to download after 12 hours only
  if [ $(($NEWTIME-$OLDTIME)) -ge 43200 ]
  then

    OLDTIME=$NEWTIME

    # Get the bing home page and search for g_img tag
    page=`/usr/bin/curl --user-agent "$USERAGENT" www.bing.com | /bin/grep g_img`
    # Get the token after g_img
    page=${page##*g_img=}
    # Check the url argument
    page=${page#*url:\'}
    # Extract the url until '
    page=${page%%\'*}

    /usr/bin/curl --user-agent "$USERAGENT" "http://www.bing.com/$page" > $FOLDER/current_background.jpg

   
  fi

done

} &

notate che ho specificato delle query come Mozilla/5.0, giusto per non far vedere che sto usando curl.

Questo script l'ho salvato come bingimg.sh e inserito in /usr/local/sbin, ovviamente come superuser, quindi ho messo la classica riga in /etc/rc.local :

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

...
/usr/local/sbin/bingimg.sh

...
exit 0

Riavviando il sistema dopo 10 minuti l'immagine è cambiata e così via, giorno per giorno ...

E se ...

E se volete salvare le immagini, allora potete giochicchiare come meglio preferite. Per esempio potete mettere nella cartella background una cartella history e con un abile colpo di tee, scrivere al posto del curl che scarica l'immagine, qualcosa tipo :

       ...
    /usr/bin/curl --user-agent "$USERAGENT" "http://www.bing.com/$page" > $FOLDER/current_background.jpg   
# Remote image name
    OUTPUT=${page##*/}

    # Download only if it does not exists 
    if [ ! -e "$FOLDER/history/$OUTPUT" ]
    then
      /usr/bin/curl --user-agent "$USERAGENT" "http://www.bing.com/$page" | /usr/bin/tee $FOLDER/history/$OUTPUT > $FOLDER/current_background.jpg
    fi

    ...

che in più ha il vantaggio di sovrascrivere l'immagine solo se questa non esiste già, e tante altre cose che vi lascio immaginare.


lunedì 26 agosto 2013

Un efficiente backup incrementale con il TAR

Pulizie d'autunno

Si avvicina il tempo dell'autunno ed è il momento di pulizie dei dischi e dell'ambiente circostante i dischi, cioè lo spazio vitale.

Tra i meandri più oscuri di tale spazio vitale, ho ritrovato decine di obsoleti CD e DVD e addirittura dei floppy disk, con tracce di antico codice TurboC scritto da giovane e di altissimo valore sentimentale, ormai semi irrecuperabili.

Ripensandoci mi è venuto in mente di salvare il salvabile da qualche parte, che non significa semplicemente salvarlo su un disco o una chiavetta a sua volta da dimenticare da qualche parte, in attesa che venga perso o cancellato, ma di organizzare un sistema di backup più modulare di quello normalmente usato per il disco e ampiamente discusso in passati articoli.

L'archiviatore ufficiale del mondo Linux come sappiamo è il Tape ARchiver che, dopo il passaggio per diverse strutture e versioni, è e sarà universalmente riconosciuto da tutti i sistemi operativi come uno standard.

Abbiamo anche visto come col tar , grazie al fatto che non si tratta di un semplice archiviatore ma di un serializzatore di oggetti del File System, sia praticamente possibile far di tutto, compreso far volare un pinguino da un computer all'altro.

Qui analizzeremo il tar dal punto di vista del backup incrementale superando alcune sostanziali inadeguatezze e costruendo uno script particolarmente interessante per chiunque voglia memorizzare i propri progetti, anche in modo incrementale, in un singolo file portabile e standard.

Come funziona il tar incrementale ?

Non è mia intenzione causare reazioni eccessive e rabbiose da parte dei puristi dei comandi *nix e nemmeno elevarmi al di sopra delle parti e giudicare severamente strumenti in uso da decenni, ma mi sento di dire che l'utilizzo di tar come sistema di backup incrementale è tecnicamente "un casino".

Sia chiaro che questo è dovuto all'estrema versatilità del comando tar e delle infinite possibilità che ci offre e grazie alle quali vedremo come risolvere parte dei nostri problemi, ma ciò non toglie che il suo comportamento standard sia piuttosto complesso da capire, tanto che molti articoli su Internet, pretendono di spiegarlo ma non sono del tutto corretti.

Vediamo allora di spiegarlo correttamente, cercando di capirne il funzionamento.

Il tar come ho detto, è un semplice serializzatore di oggetti del File System, quindi scansiona i rami del File System e scrive in uno stream una sequenza, che può essere recuperata in modo da ricostruire altrove e/o poi gli stessi rami. L'archiviatore in sé, non comprime ma passa lo stream ad un semplice filtro.

Questo porta ad innumerevoli vantaggi in fatto di versatilità ma anche come fattore di compressione, specie quando si ha a che fare con molti files di testo in quanto, a differenza per esempio da un semplice zip, dove i files sono compressi singolarmente e poi aggiunti, qui i files sono compressi nella globalità e considerato che il buffer di un bzip2 (opzione best) è di circa 1M, consente di scendere ad un entropia infinitesimale.

Per contro si deve dire che a differenza di uno zip, una volta che si ha il prodotto compresso, non è possibile modificarlo (aggiungere, togliere o fare update), senza prima decomprimerlo e ciò può essere molto scomodo se non si ha abbastanza spazio.

Per quanto riguarda il backup incrementale il tar offre un semplice flag denominato --listed-incremental, da non confondersi con --incremental che è riferito al vecchio sistema, e già il fatto che siano due fa capire che tale vicenda è molto travagliata.

Capire cosa fa esattamente questo flag che deve essere usato con un nome file, cioè come :

--listed-incremental=<file>

è importante, perché molti lo trattano come se compisse mirabili operazioni nascoste.

In realtà produce una semplice lista, che non è nemmeno in formato testo ma è una specie di dump binario delle strutture indice, e non dà quasi nessuna indicazione sul file salvato.

È in sostanza una lista simile a quella che si potrebbe ricavare col un semplice find anche se con qualche controllo in più.

Fase 1 - Il primo tarball 

Consideriamo l'ipotetica cartella "saveme".

Per eseguire un tar incrementale si può procedere in questo modo :

tar cvfz saveme-20130826123545.tgz \
     --listed-incremental=saveme-20130826123545.idx \
     saveme


Il prodotto della suddetta operazione saranno ben due files :

saveme-20130826123545.tgz
saveme-20130826123545.idx

Il primo contenente il vero tarball e il secondo con l'indice dei files o lo stato del file system o in qualsiasi altro modo volete chiamarlo.

Per chi se lo chiedesse il valore 20130826123545 si ricava così :

date +%Y%m%d%H%M%S

ed è una comodissima "data ordinabile".

Fase 2 - Aggiornamento

Ipotizziamo di fare alcune modifiche alla cartella "saveme", aggiungendo, spostando e togliendo files.

Per aggiornare il backup ci serve il vecchio indice, cioè l'ultimo che abbiamo salvato.

In caso non volessimo tenere una storia di tutto il file system, ma usare un semplice backup incrementale, allora potremmo usare un indice unico, ma non conviene, in quanto gli indici sono di dimensioni molto ridotte, e con essi è possibile tenersi l'effettiva storia di una cartella e ripristinarla in qualsiasi momento del suo passato

La scelta più semplice è quindi trovare la nuova data e copiare l'indice :

cp saveme-20130826123545.idx saveme-20130826152632.idx 

e quindi

tar cvfz saveme-20130826152632.tgz \
     --listed-incremental=saveme-20130826
152632.idx \
     saveme


Quest'ultima operazione, prenderà in considerazione l'indice appena copiato ed eseguirà il backup dei soli files modificati in base al timestamp, quindi aggiornerà l'indice con il nuovo stato (di tutti i files), con i files in più e omettendo chiaramente quelli cancellati.

E i files presenti diventeranno quattro :

saveme-20130826123545.tgz
saveme-20130826123545.idx
saveme-20130826152632.tgz
saveme-20130826152632.idx

Nonostante la considerazione che i tarball sono comunque semplici tarball e possono essere estratti indipendentemente dagli indici, il fatto che files aumentino a dismisura e che tali indici restino separati, non è affatto una cosa positiva e introduce evidenti svantaggi dal punto di vista della gestibilità del backup e nella sua archiviazione.

Fase 3 - Restore

Per ripristinare lo stato di un progetto in un certo istante temporale, per esempio le 15.26.32 del 26/08/2013 (cioè l'ultimo), dobbiamo procedere solo sull'indice interessato ed estrarre tutti i backup fino a questo indice, in questo modo :

tar xvfz saveme-20130826123545.tgz \
     --listed-incremental=saveme-20130826
152632.idx \
     saveme

tar xvfz saveme-20130826152632.tgz \
     --listed-incremental=saveme-20130826
152632.idx \
     saveme


La logica di questa operazione è molto particolare, infatti il tar usa l'indice, solo per cancellare dal file system i files che non si trovano nell'indice stesso.

Per spiegarci meglio, immaginiamo che al primo backup in saveme, ci fossero tre files , A , B  e C .

Immaginiamo che prima di fare il secondo backup, avessimo tolto B , aggiornato C e aggiunto un file D.

L'indice 20130826152632 a questo punto, conterrebbe l'elenco : A, C, D .

Durante l'estrazione del primo tarball, che conterrebbe A,B e C , tutti i files sarebbero estratti, in quanto non ci sarebbe nulla da cancellare, curiosamente anche B che non si trova nell'indice.

Al secondo passaggio B sarebbe cancellato, e sarebbero estratti sempre tutti i files contenuti nel secondo tarball e cioè C che sarebbe così sovrascritto e come file nuovo, ripristinando lo stato del sistema.


Quindi l'archiviatore, non ricostruisce lo stato del sistema ma cerca di ripristinarlo con strani passaggi cancellando e sovrascrivendo più volte, con la scusa che l'hard disk di solito è trasparente a queste azioni (grazie alle fantastiche buffer cache).

Bisognerebbe chiedere a quelli che usano i DOM o in generale le Flash, magari con appositi file systems a rotazione se sono d'accordo, ma come al solito non si può pretendere tutto dalla vita.

Un po`d'ordine nel chaos

Cercando di comprendere il tutto e di fare un po`d'ordine nel chaos, mi rifaccio a uno dei primi progetti che ho descritto tra queste pagine, cioè Time Archive che usa un sistema di patch differenziali, sui tar binari di progetto e che si è rivelato ottimo per piccole modifiche, ma piuttosto dispendioso su grosse variazioni.

L'idea è quella di introdurre praticamente gli stessi comandi, anzi volendo di creare una nuova versione di Time Archive , e di chiamare quella vecchia per esempio DiffArchive o qualcosa del genere, usando semplicemente e solamente il concetto di tar incrementale .

I comandi da implementare sono i 4 di Time Archive , cioè U per update, R per rollback , X per extract e T per trace.

Gli scopi di questo progetto sono interessanti :
  1. Definire uno standard per i backup.
  2. Automatizzare le procedure.
  3. Mantenere l'affidabilità e il formato del tar con compressione bzip2.
  4. Usare un solo file per ogni progetto che mantenga la storia e le versioni.
In particolare per il punto 4, useremo un semplice tar non compresso che conterrà tutti i tar compressi, in ordine con indici e descrizioni. Il fatto che non sia compresso implicherà la sua facile modificabilità e affidabilità.

TimeArchive II

Il comando Update

Il comando update per questo timearchive si definisce come nella precedente versione :
timearchive U <archive> <folder> [ "<description>" ]
dove archive è il nome dell'archivio arbitrario che dovrà ospitare tutti gli altri archivi, folder è la cartella da archiviare e description è una breve descrizione opzionale della versione corrente.

Dal punto di vista logico, si individuano innanzi tutto il folder e l'archivio in termini assoluti, poi si può procedere con un codice come questo :

 tmpdir=`mktemp -d`
 todate=`date +%Y%m%d%H%M%S`

 if [ -e "$archfull" ]
 then
    lastidx=`tar tf "$archfull" | sort | grep idx | tail -n 1`
    tar xf $archfull $lastidx -O >$tmpdir/$todate.idx
 fi
 

 tar cfj $tmpdir/$todate.tb2 -C "${dirfull%/*}" --listed-incremental=$tmpdir/$todate.idx "${dirfull##*/}"
 

 # Update archive
 echo $4 >$tmpdir/$todate.txt
 tar -C $tmpdir -rf $archfull $todate.tb2
 tar -C $tmpdir -rf $archfull $todate.txt
 tar -C $tmpdir -rf $archfull $todate.idx
 rm $tmpdir/*
 rmdir $tmpdir

In sostanza si crea una cartella temporanea di lavoro e si determina la data. Se l'archivio esiste già, è estratto direttamente dal tar l'ultimo indice salvato, in questo modo :

    lastidx=`tar tf "$archfull" | sort | grep idx | tail -n 1`

Se invece l'archivio non esiste, l'indice sarà creato.

Poi c'è un tar che esegue il backup incrementale e alla fine i due files tarball , indice e un file contenente semplicemente l'echo della description, sono appesi al file (-rf) archivio principale, che se non c'è è ovviamente creato sul momento.

Quindi per ogni versione avremo l'aggiunta di tre files ad un file archivio principale, facilmente verificabile con :
tar tvf archive

Il comando eXtract

La sintassi del comando è :

timearchive X <archive> <folder> [ <date> ]
Dove archive è il solito archivio, folder  è il folder dove sarà estratta la cartella del progetto indicata prima, cioè se la cartella era per esempio Pictures indicando /tmp , troveremo in /tmp la Picures. Per ripristinarla nella cartella corrente basta indicare come folder il "." .

Infine date è la data che si vuol ripristinare ed è opzionale.

Estrarre il contenuto dell'archivio richiede l'estrazione di tutti i tarball fino ad una data specifica ed è espressa dal seguente blocco di codice :

  tmpfile=`mktemp`
  if [ -z "$4" ]
  then
    lastidx=`tar tf "$archfull" | sort | grep idx | tail -n 1`
  else
    lastidx=`tar tf "$archfull" | grep "$4.idx"`
    if [ -z "$lastidx" ]
    then
       echo "Date does not match"
       exit
    fi
  fi
  tar xf $archfull $lastidx -O >$tmpfile
  cd "$dirfull"
  tar tf $archfull | grep tb2 | tarext "$archfull" "$tmpfile" "$4"
  rm $tmpfile
A parte la creazione del file temporaneo che ci servirà per l'indice, con  -z "$4" si verifica se il quarto parametro e cioè la Date è vuota o meno.

Se è vuota si ricava l'ultimo indice, come nel caso dell'update, altrimenti l'indice è cercato esplicitamente (e se non si trova si ha un errore).

Estratto l'indice nel file temporaneo si analizza semplicemente il contenuto dell'archivio, si ordina in ordine crescente di data e si passano i nomi dei relativi tarball ad una funzione chiamata tarext .

Il tarext fa questo :
function tarext
{
  while read a
  do
    tar xfp "$1" "$a" -O | tar xj --listed-incremental="$2"
    if [ ! -z "$3" ]
    then
      if [ "$3.tb2" == $a ]
      then
        return
      fi
    fi
  done
}
ossia prosegue estraendo coerentemente tutti i tar sull'indice indicato fino a quando ha estratto quello giusto (che può essere anche l'ultimo), ricostruendo così lo stato in un preciso istante di tempo.

Notare che il tarball, in questo caso non è copiato su disco ma estratto in una pipe e il folder ricostruito senza occupare ulteriore spazio.

Il comando Rollback

Il comando rollback ripristina l'archivio ad una data prescelta che significa la cancellazione di tutti le successive versioni. È un comando che si usa raramente,  per esempio quando si sbaglia a fare un update.

La sintassi è semplicemente:
timearchive R <archive> <date>
Il funzionamento è piuttosto simile a extract :
if [ -z "$3" ]
  then
     echo "Missing rollback date"
     exit
  fi   
lastidx=`tar tf "$archfull" | grep "$3.idx"`
if [ -z "$lastidx" ]
then
   echo "Date does not match"
   exit
fi
tar tf $archfull | sort -r | rollback "$archfull" "$3" 

 

Si noti però che il sort è rovesciato, quindi sono cancellati tutti i files a partire dal fondo fino alla data scelta.  Chi li cancella è la seguente procedura :

function rollback
{
  while read a
  do       
    if [ "$a" == "$2.txt" ]
    then
      return
    fi     
    tar --delete --file "$1" "$a"
  done
}

Anche qui simile alla precedente ma tenendo conto dell'ordine inverso e dell'uscita prima e non dopo la data prescelta.

Non si può ovviamente fare il rollback ad una data inesistente, e cancellare il primo record, per fare quello basta cancellare l'archivio.

Il comando Trace

Mostra il contenuto dell'archivio. La sua sintassi è :
timearchive T <archive>
e il suo funzionamento è basato su una riga di codice  :
tar tf $2 | sort | grep txt | showcontent "$2"
e una funzione :

function showcontent
{
  while read l
  do
    echo -n ${l%%\.*}"  "
    tar xf $1 $l -O
  done
}

la quale, come possiamo osservare, mostra la data e il commento opzionale inserito durante l'update.

Se il commento non è stato inserito, il file è comunque presente in quanto echo, come una stringa vuota.

Lo script finale


Ed eccoci al consueto script complessivo che implementa il comando :


#!/bin/bash

function showcontent
{
  while read l
  do
    echo -n ${l%%\.*}"  "
    tar xf $1 $l -O
  done
}


function rollback
{
  while read a
  do      
    if [ "$a" == "$2.txt" ]
    then
      return
    fi    
    tar --delete --file "$1" "$a"
  done
}


function tarext
{
  while read a
  do
    tar xfp "$1" "$a" -O | tar xj --listed-incremental="$2"
    if [ ! -z "$3" ]
    then
      if [ "$3.tb2" == $a ]
      then
        return
      fi
    fi
  done
}


case $1 in

U)
  dirfull=$3
  if [ "${dirfull:0:1}" != "/" ]
  then
    dirfull=`pwd`/$dirfull
  fi
  if [ ! -d  "$dirfull" ]
  then
    echo "$3 must be an existing directory"
    exit
  fi
  archfull=$2
  if [ "${archfull:0:1}" != "/" ]
  then
    archfull=`pwd`/$archfull
  fi
  tmpdir=`mktemp -d`
  todate=`date +%Y%m%d%H%M%S`
  if [ -e "$archfull" ]
  then
    lastidx=`tar tf "$archfull" | sort | grep idx | tail -n 1`
    tar xf $archfull $lastidx -O >$tmpdir/$todate.idx
  fi
  tar cfj $tmpdir/$todate.tb2 -C "${dirfull%/*}" --listed-incremental=$tmpdir/$todate.idx "${dirfull##*/}"
  # Update archive
  echo $4 >$tmpdir/$todate.txt
  tar -C $tmpdir -rf $archfull $todate.tb2
  tar -C $tmpdir -rf $archfull $todate.txt
  tar -C $tmpdir -rf $archfull $todate.idx
  rm $tmpdir/*
  rmdir $tmpdir
;;

X)
  dirfull=$3
  if [ "${dirfull:0:1}" != "/" ]
  then
    dirfull=`pwd`/$dirfull
  fi
  if [ ! -d  $dirfull ]
  then
    echo "$3 must be an existing directory"
    exit
  fi
  archfull=$2
  if [ "${archfull:0:1}" != "/" ]
  then
    archfull=`pwd`/$archfull
  fi
  if [ ! -e $archfull ]
  then
     echo "Archive not found"
     exit
  fi
  tmpfile=`mktemp`
  if [ -z "$4" ]
  then
    lastidx=`tar tf "$archfull" | sort | grep idx | tail -n 1`
  else
    lastidx=`tar tf "$archfull" | grep "$4.idx"`
    if [ -z "$lastidx" ]
    then
       echo "Date does not match"
       exit
    fi
  fi
  tar xf $archfull $lastidx -O >$tmpfile
  cd "$dirfull"
  tar tf $archfull | grep tb2 | tarext "$archfull" "$tmpfile" "$4"
  rm $tmpfile
;;

R)
  archfull=$2
  if [ "${archfull:0:1}" != "/" ]
  then
    archfull=`pwd`/$archfull
  fi
  if [ ! -e $archfull ]
  then
     echo "Archive not found"
     exit
  fi
  if [ -z "$3" ]
  then
     echo "Missing rollback date"
     exit
  fi   
  lastidx=`tar tf "$archfull" | grep "$3.idx"`
  if [ -z "$lastidx" ]
  then
     echo "Date does not match"
     exit
  fi
  tar tf $archfull | sort -r | rollback "$archfull" "$3" 
;;

T)
    tar tf $2 | sort | grep txt | showcontent "$2"
;;

*)
  echo Bad paramenter, please use U,T,R or X.
;;
esac

con questa evoluzione del timearchive, ho ottenuto ottimi risultati specie su backup significativi e complessi e il risultato è comunque un tar, facilmente gestibile in caso di emergenza o trasferimento su altri sistemi.