Basi di Linux - Un piccolo programma per il backup automatico
September 21, 2007
Un piccolo programma per il backup automatico
Proviamo adesso ad utilizzare i comandi utili per la compattazione e la compressione di file e di intere directory. Il comando tar ci consente di compattare un’intera directory in un singolo file. Per esempio, creiamo una directory:
[roberto@diamondhead roberto]$ mkdir mio_archivio
e creiamo all’interno di questa dei file:
[roberto@diamondhead roberto]$ touch mio_archivio/edit1.txt
[roberto@diamondhead roberto]$ touch mio_archivio/edit2.txt
[roberto@diamondhead roberto]$ touch mio_archivio/edit3.txt
ora con il comando tar compattiamo la directory mio_archivio in modo da avere un singolo file:
[roberto@diamondhead roberto]$ tar cvf mio_archivio.tar mio_archivio
ora abbiamo compattato in un solo file il contenuto della directory mio_archivio, ma non l’abbiamo ancora compresso. Per fare questa operazione diamo questo comando:
[roberto@diamondhead roberto]$ gzip mio_archivio.tar
il file ottenuto con estensione .gz è praticamente il risultato di queste operazioni: abbiamo ottenuto un archivio compresso. Per ritornare alla directory originale si deve unzippare il file compresso mio_archivio.tar.gz in questo modo:
[roberto@diamondhead roberto]$ gzip -dvr mio_archivio.tar.gz
ed espandere il file così ottenuto:
[roberto@diamondhead roberto]$ tar xvf mio_archivio.tar
Un’altro comando molto utile (che abbiamo già visto) è l’mv che sta per move. Possiamo cambiare nome ad un file o ad una directory o trasferirla in un’altra zona del file system:
[roberto@diamondhead roberto]$ mv mio_archivio mio_archivio_new
altro comando utile è il cp, che copia un file o una directory:
[roberto@diamondhead roberto]$ touch pippo
[roberto@diamondhead roberto]$ cp pippo pippo_bis
TEST1: Provate ora a creare uno script shell in grado di prendere una directory prestabilita (facciamo mio_archivio), dove supponiamo che in essa sia contenuto tutto il nostro lavoro, e di eseguire un backup di quest’ultima nella stessa directory dove ci troviamo. Sareste in grado di farlo?
Risposta -> Lo script avrà una serie di istruzioni come queste:
#!/bin/bash
echo “Inizio archiviazione del file : mio_archivio”
echo “Nella directory : /home/roberto/”
# archiviazione e compressione file
tar cvf /home/roberto/mio_archivio.tar /home/roberto/mio_archivio
gzip /home/roberto/mio_archivio.tar
Questo script shell esegue un tar di mio_archivio, dopodichè lo zippa nella directory prestabilita. Ho preparato uno script che faremo assieme. Proviamo ora a modificare lo script appena fatto in modo che le directory siano contenute in delle variabili, e le operazioni devono essere fatte su di esse. Stabiliamo anche che i vecchi backup non devono essere cancellati, ma numerati per esempio dalla data odierna. Inoltre, se durante queste operazioni si manifestano degli errori, redirezionare lo standard error in un file che chiameremo error.txt ed un eventuale standard output (tipico dei comandi come gzip e tar) nel device null:
#!/bin/bash
# path assoluto dove si trova l’archivio
DIR=/home/roberto/
# nome dell’archivio
ARCHIVIO=mio_archivio
# path + nome archivio
OF=$DIR$ARCHIVIO
# nome del file di errori
ERROR=error.txt
# definizione della data corrente
APPEND=$(date +%Y%m%d%H%M%S)
echo “Inizio archiviazione del file :”$ARCHIVIO
echo “Nella directory :”$DIR
# archiviazione e compressione file
tar cvf $OF-$APPEND.tar $OF 1> /dev/null 2> $DIR$ERROR
gzip $OF-$APPEND.tar 1> /dev/null 2>> $DIR$ERROR
TEST2: proviamo adesso a modificare lo script in modo da copiare l’archivio ottenuto in una directory prestabilita, che chiameremo backup, e gli errori eventuali sulla directory error:
#!/bin/bash
# path assoluto dove si trova l’archivio
DIR=/home/roberto/
# nome dell’archivio
ARCHIVIO=mio_archivio
# path + nome archivio
OF=$DIR$ARCHIVIO
# nome della directory degli errori
ERROR_DIR=error/
# nome del file di errori
ERROR=error.txt
# nome della directory di backup
BACKUP=backup/
# definizione della data corrente
APPEND=$(date +%Y%m%d%H%M%S)
echo “Inizio archiviazione del file :”$ARCHIVIO
echo “Nella directory :”$DIR$BACKUP
# archiviazione e compressione file
tar cvf $DIR$BACKUP$ARCHIVIO-$APPEND.tar $OF 1> /dev/null 2>
$DIR$ERROR_DIR$ERROR
gzip $DIR$BACKUP$ARCHIVIO-$APPEND.tar 1> /dev/null 2>> $DIR$ERROR_DIR$ERROR
Il nostro programma di backup non è abbastanza solido. Se per esempio la directory backup viene cancellata per errore il programma si ferma.
(provare a mandarlo in esecuzione senza la directory di backup e vedere gli errori riportati nel file error/error.txt).
Per renderlo più robusto dovremo controllare se esistono le directory dell’archivio mio_archivio, backup ed error e crearle in caso contrario:
#!/bin/bash
# path assoluto dove si trova l’archivio
DIR=/home/roberto/
# nome dell’archivio
ARCHIVIO=mio_archivio
# path + nome archivio
OF=$DIR$ARCHIVIO
# nome della directory degli errori
ERROR_DIR=error/
# nome del file di errori
ERROR=error.txt
# nome della directory di backup
BACKUP=backup/
# definizione della data corrente
APPEND=$(date +%Y%m%d%H%M%S)
# controllo se esiste le directory mio_archivio
# se non esistone procedi con la creazione
if [ -x $OF ]
then
echo “La directory $OF esiste, procedo con la compressione”
else
echo “La directory $OF non esiste!”
exit
fi
echo “————————————————”
# controllo se esiste le directory error e backup
# se non esistono procedi con la creazione
if [ -x $DIR$ERROR_DIR ]
then
echo “La directory $ERROR_DIR esiste, procedo con la scrittura di eventu
ali errori”
else
mkdir $DIR$ERROR_DIR
echo “Directory degli errori creata”
fi
if [ -x $DIR$BACKUP ]
then
echo “La directory $BACKUP esiste, procedo con la scrittura dell’archivi
o”
else
mkdir $DIR$BACKUP
echo “Directory dei backup creata”
fi
echo “Inizio archiviazione del file :”$ARCHIVIO
echo “nella directory :”$DIR$BACKUP
# archiviazione e compressione file
tar cvf $DIR$BACKUP$ARCHIVIO-$APPEND.tar $OF 1> /dev/null 2> $DIR$ERROR_DIR$ERRO
R
gzip $DIR$BACKUP$ARCHIVIO-$APPEND.tar 1> /dev/null 2>> $DIR$ERROR_DIR$ERROR
ora il programma è abbastanza robusto e può reggere bene da situazioni impreviste, come la mancanza delle directory di riferimento. Possiamo utilizzare adesso il programma crontab per schedulare il nostro script ad intervalli regolari in modo da creare un backup della nostra cartella di lavoro, diciamo ogni ora. Prima di tutto dobbiamo preoccuparci che il demone crond sia in esecuzione:
[roberto@diamondhead roberto]$ ps -ef | grep crond
root 1008 1 0 08:28 ? 00:00:00 crond
roberto 1731 1656 0 10:39 pts/2 00:00:00 grep crond
poi modifichiamo (se non esiste lo creiamo) il file cron.allow dentro /etc come amministratore di sistema, e ci aggiungiamo gli utenti abilitati al suo utilizzo:
roberto
root
Effettuiamo adesso l’editazione del crontab del nostro utente:
[roberto@diamondhead roberto]$ crontab -e
e aggiungiamo la riga:
0 * * * * /home/roberto/script.sh
il primo campo definisce i minuti (0-59), il secondo specifica l’ora (0-23), il terzo al giorno del mese (1-31), il quarto è il mese (112), il quinto campo è il giorno della settimana (0-6) dove 0 corrisponde alla domenica.
Se per esempio volessimo eseguire lo script alle 2 di ogni notte dal lunedi al venerdi dovremo impostare una riga del tipo:
0 2 * * 1-5 /home/roberto/script.sh
Per vedere quali jobs sono in elenco nel crontab basta digitare:
[roberto@diamondhead roberto]$ crontab -l
se si è root e si vuole editare il crontab di un utente basta specificare quest’ultimo preceduto dall’opzione -u:
[root@diamondhead /root]# crontab -u roberto -e
Tutti i file che contengono la lista di cose da fare di crontab vengono archiviati nella directory:
[root@diamondhead /root]# cd /var/spool/cron/
dove ogni file ha il nome dell’utente che lo ha creato. Se si vuole editare il file di crontab si deve utilizzare esclusivamente crontab -e; non si deve editare direttamente il file.
Se vogliamo cancellare il nostro file crontab dobbiamo utilizzare:
[roberto@diamondhead roberto]$ crontab -r
Un’altra funzione interessante della shell bash è quella che permettere di specificare a linea di comando dei parametri. Se per esempio vogliamo stampare un qualcosa specificato subito dopo il nome dello script, possiamo fare:
#!/bin/bash
if [ -z “$1″ ]; then
echo “uso: $0 file”
exit
fi
echo “Nome del File:$1″
il flag -z indica se la variabile è vuota, ed in questo caso ne mostra il funzionamento (notare che viene stampato il nome dello script grazie alla variabile $0 che è il primo parametro). Alla fine viene stampato il nome specificato subito dopo lo script, se questo esiste.
TEST3: In base a quello che avete appreso fino a questo punto, provate a realizzare un sistema di backup simile a quello che abbiamo creato, ma deve creare copie di backup con directory specificate a linea di comando. Il programma registra sempre gli errori su error/error.txt e il backup sulla directory backup/. Prestare particolare attenzione al percorso assoluto che in questo caso diventa relativo visto che si specifica il file direttamente.
Esempio già pronto:
#!/bin/bash
if [ -z “$1″ ]; then
echo “uso: $0 directory di backup”
exit
fi
# nome della directory degli errori
ERROR_DIR=error/
# nome del file di errori
ERROR=error.txt
# nome della directory di backup
BACKUP=backup/
# definizione della data corrente
APPEND=$(date +%Y%m%d%H%M%S)
# controllo se esiste le directory $1
# se non esistone procedi con la creazione
if [ -x $1 ]
then
echo “La directory esiste, procedo con la compressione”
else
echo “La directory $1 non esiste!”
exit
fi
echo “————————————————”
# controllo se esiste le directory error e backup
# se non esistono procedi con la creazione
if [ -x $ERROR_DIR ]
then
echo “La directory $ERROR_DIR esiste, procedo con la scrittura di eventuali errori”
else
mkdir $ERROR_DIR
echo “Directory degli errori creata”
fi
if [ -x $BACKUP ]
then
echo “La directory $BACKUP esiste, procedo con la scrittura dell’archivi
o”
else
mkdir $BACKUP
echo “Directory dei backup creata”
fi
echo “Inizio archiviazione del file :”$1
echo “nella directory :”$BACKUP
# archiviazione e compressione file
tar cvf $BACKUP$1-$APPEND.tar $1 1> /dev/null 2> $ERROR_DIR$ERROR
gzip $BACKUP$1-$APPEND.tar 1> /dev/null 2>> $ERROR_DIR$ERROR
Permessi di accesso ai file e alle directory, utenti e gruppi
Digitando nella propria home directory il comando:
[roberto@diamondhead roberto]$ ls -l
totale 48
drwxr-xr-x 2 roberto roberto 4096 mag 6 15:26 backup
drwxr-xr-x 3 roberto roberto 4096 mag 2 17:26 Desktop
drwxr-xr-x 2 roberto roberto 4096 mag 6 15:25 error
-rw——-1 roberto roberto 409 mag 2 17:41 mbox
drwxrwxr-x 2 roberto roberto 4096 mag 5 19:40 mio_archivio
drwx——2 roberto roberto 4096 mag 2 15:34 nsmail
-rwxrwxr-x 1 roberto roberto 662 mag 5 20:07 script1a.sh
….
oltre ai nomi di file e directory si vedranno tutta una serie di permessi nella prima colonna, il nome del proprietario nella terza (roberto), ed il gruppo nella quarta (roberto). Seguono poi altre informazioni che riguardano la data di creazione del file. Valutiamo la prima riga. Abbiamo una serie di valori drwxr-xr-x disposti su 4 colonne: la prima è formata da una lettera, in questo caso la “d” sta a significare che si tratta di una directory. Segue poi una colonna composta da tre elementi rwx. Questi sono i permessi del proprietario della directory che in questo caso sono di lettura (read), scrittura (write) e di accesso (execute). Nella colonna che segue abbiamo altre tre lettere che indicano i permessi del gruppo, che in questo caso può solo leggere e accedere alla directory. L’ultima colonna, anche questa composta da tre lettere, riguardano i permessi per gli altri utenti del sistema.
Allora ricapitolando: la prima colonna, composta da 1 carattere, indica se il file è una directory (allora avremo una “d”), oppure un file normale (in questo caso avremo un “-”). Poi l’altra colonna è composta da 3 caratteri, che identifica i permessi del proprietario e può essere di lettura (r), scrittura (w) o di esecuzione (x) per i file, o di accesso per le directory. L’altra colonna, sempre composta da tre caratteri, sono i permessi del gruppo, e l’ultima colonna si riferisce ai permessi di tutti gli altri utenti.
Ho parlato di utenti di sistema e gruppi. Gli utenti di sistema generalmente hanno accesso al sistema e questi si possono organizzare in gruppi. Per esempio creiamo un nuovo utente da root:
[root@diamondhead /root]# adduser marco
e stabiliamo la password:
[root@diamondhead /root]# passwd marco
Changing password for user marco
New UNIX password:pippo
Retype new UNIX password:pippo
passwd: all authentication tokens updated successfully
ora se andiamo a controllare il contenuto del file /etc/passwd vedremo che il nuovo utente è nell’elenco assieme al nostro:
[root@diamondhead /root]# more /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:
daemon:x:2:2:daemon:/sbin:
adm:x:3:4:adm:/var/adm:
…
squid:x:23:23::/var/spool/squid:/dev/null
roberto:x:500:500::/home/roberto:/bin/bash
paola:x:501:501::/home/paola:/bin/bash
marco:x:502:502::/home/marco:/bin/bash
in questo file il primo campo identifica l’utente (massimo 8 caratteri), il secondo identifica la password (in questo sistema linux è installata l’utility shadow che permette di nascondere la password in un’altro file dentro /etc/shadow), poi segue l’userID che identifica univocalmente l’utente grazie ad un numero (non deve essere 0 perchè è associato all’utente root), poi abbiamo il groupID che ci identifica in un gruppo di appartenenza, poi ancora abbiamo la possibilità di creare per ogni utente informazioni personali, come il vero nome dell’utente, il numero di telefono e così via (in questo caso non abbiamo nessuna informazione per i nostri utenti), poi abbiamo la directory home dell’utente e per finire la shell utilizzata per l’utente, che come abbiamo visto possono essere scelte tra quelle disponibili dal nostro sistema e si possono consultare dentro la directory /etc/shells.
Ora, se vogliamo far appartenere l’utente marco ad un gruppo, magari assieme ad altri utenti, visto che magari marco fa parte del team di lavoro di un progetto, possiamo creare questo gruppo (ovviamente da utente root) con il comando:
[root@diamondhead /root]# groupadd works
adesso facendo un:
[root@diamondhead /root]# more /etc/group
verranno visualizzati tutti i gruppi del sistema compreso quello appena creato: il gruppo works con GID 504. Ora se vogliamo far parte l’utente marco del gruppo works non dovremo fare altro che editare il file:
[root@diamondhead /root]# vi /etc/group
e aggiungere subito dopo al “:” del group ID gli utenti relativi:
works:x:504:marco,roberto (non mettere support lo faranno loro….)
adesso salviamo e usciamo dal terminale. Facciamo nuovamente il login però con l’utente marco e vedremo che digitando:
[marco@diamondhead marco]$ id
uid=502(marco) gid=502(marco) gruppi=502(marco),504(works)
l’UID di marco è 502, fa parte dello stesso gruppo del suo UID, ma
fa anche parte del gruppo works con GID 504.
TEST4: Provate ora a far appartenere il vostro utente support al gruppo works.
_ . _ . _ . _
(si presuppone che gli allievi siano riusciti a far appartenere l’utente support al gruppo works)
Loggatevi tutti come support e andate nella vostra home directory. Digitare:
[roberto@diamondhead roberto]$ ls -l
qui abbiamo i vostri file con i relativi permessi. Troviamo in particolare il file prova2.sh che ha questi permessi:
-rwxrwxrwx 1 roberto roberto 101 mag 8 10:59 prova2.sh
in questo caso il file script prova2.sh è effettivamente un file, notale il trattino sulla prima colonna, poi ha i permessi di lettura-scritturaesecuzione per il proprietario, i permessi di lettura-scritturaesecuzione per il gruppo, che in questo caso è sempre lo stesso del proprietario, e i permessi di lettura-scrittura-esecuzione per tutti gli altri utenti del sistema.
Adesso vogliamo fare in modo che solo il nostro utente possa mandare in esecuzione lo script. Come facciamo? Scriviamo:
[roberto@diamondhead roberto]$ chmod 766 prova2.sh
diamo un:
[roberto@diamondhead roberto]$ ls -la
e vedremo che la lettera x di esecuzione c’è solo nel proprietario del file:
…
-rwxrw-rw-1 roberto roberto 101 mag 8 10:59 prova2.sh
…
Che cosa vuol dire quel 766 subito dopo chmod? Chi è che lo sa?
Allora, considerate che il numero ottale 1 sta per esecuzione, il numero ottale 2 sta per scrittura, ed il numero ottale 4 sta per lettura. Se combiniamo questi numeri tra di loro possiamo avere tutte le combinazioni per i permessi relativi al proprietario, al gruppo e a tutti gli altri.
Per esempio se vogliamo negare anche la possibilità di scrivere il file prova2.sh per tutti gli altri utenti e dare solo a questi i permessi di lettura dovremo scrivere:
[roberto@diamondhead roberto]$ chmod 764 prova2.sh
noteremo con un ls -l che il file prova2.sh ora ha solo i permessi di lettura per tutti gli altri utenti (vedere le ultime 3 lettere).
Consideriamo il primo numero di chmod 764 e cioè 7. Per il proprietario abbiamo i permessi di lettura = 4 + i permessi di scrittura = 2 + i permessi di esecuzione = 1 che in totale fa appunto 7. Per il secondo numero 6 (riferito ai permessi del gruppo) abbiamo i permessi di lettura = 4 + i permessi di scrittura = 2 che in totale fa appunto 6. Continuiamo poi con il numero 4 relativi ai permessi di tutti gli altri utenti: e si riferisce al solo permesso di lettura. Per quel che riguarda le directory, visto che non sono eseguibili, la x di execute sta ad indicare l’accesso a essa. Quindi se vogliamo abilitare o disabilitare ad un utente o ad altri l’accesso ad una directory, non dovremo fare altro che mettere o togliere la x, dai permessi di quella directory. C’è un’altro sistema per attribuire i permessi ai file, cioè quello con le lettere.
Se digitiamo:
[roberto@diamondhead roberto]$ chmod g-w prova2.sh
toglieremo al gruppo i permessi di scrittura del file prova2.sh. Provate a fare un ls -l per controllare che effettivamente questo è avvenuto. Per aggiungere nuovamente i permessi di scrittura al gruppo scriveremo:
[roberto@diamondhead roberto]$ chmod g+w prova2.sh
quindi quel - e quel + sta per togliere e aggiungere rispettivamente i permessi specificati subito dopo. Se si volesse modificare i permessi all’utente, al posto della g si utilizzerebbe la lettera u mentre per gli altri utenti la lettera è la o (la o sta per other). Possiamo anche dare i permessi di scrittura sia per il proprietario, per il gruppo e per gli altri utenti con un comando solo:
[roberto@diamondhead roberto]$ chmod a+x prova2.sh
la lettera a sta ad indicare tutti (il proprietario, il gruppo e gli altri).
Possiamo anche combinare le cose facendo un:
[roberto@diamondhead roberto]$ chmod ug-x prova2.sh
in questo caso abbiamo tolto il permesso di esecuzione al proprietario e al gruppo lasciando invariati i permessi per gli altri utenti.
TEST5: Provate ora a creare 3 file vuoti + una directory.
Il primo file deve avere i permessi di lettura, scrittura ed
esecuzione per il proprietario, e nessun altro permesso per il gruppo e gli altri. Il secondo file deve avere i permessi di scrittura per il proprietario e lettura per il gruppo. Nessun permesso per gli altri. Il terzo file deve avere tutti i permessi di lettura scrittura ed esecuzione solo per gli altri utenti. La directory dovrà avere i permessi di lettura, scrittura ed accesso al proprietario, lettura ed accesso per il gruppo e solo accesso per gli altri utenti.










Leave a Reply