Una delle caratteristiche della filosofia di Unix è che l'impostazione del sistema non vuole prevedere tutte le necessità dell'utente, ma tenta di rendere semplice per ciascuno modificarsi l'ambiente a seconda delle proprie necessità.
Ogni shell prevede uno o più "file di configurazione" che viene processato ogni volta che viene invocata. Di fatto, gli script di inizializzazione di una shell, sono normali script che si eseguono all'avvio delle shell stessa.
Questi file di configurazione sono noti anche come "file init", "file rc"" (per "run control", controllo dell'esecuzione) o anche "file punto", perché il loro nome di solito inizia con ".".
La shell di default di Linux è la bash.
I file di configurazione della bash di default sono:
/etc/bashrc
: Contiene gli alias e le funzioni valide per l'intero sistema;
/etc/profile
: Contiene le variabili d'ambiente per l'intero sistema e i programmi di avvio;
$HOME/.bashrc
: Contiene gli alias e le funzioni dell'utente;
$HOME/.bash_profile
: Contiene le variabili d'ambiente e i programmi di avvio dell'utente;
$HOME/.inputrc
: Contiene definizioni di tasti e altre funzioni.
Per personalizzare il proprio ambiente bash è necessario modificare il file $HOME/.bashrc
.
E' possibile creare alias per comandi che vengono usati spesso (alias "alias"= "comando") o modificare il prompt utilizzando il linguaggio bash o eseguire determinati programmi all'avvio della shell ecc.
Oltre agli script eseguiti al login, la shell può eseguire uno script al momento del logout da parte dell'utente.
Per la bash, questo script, se esiste, è : $HOME/.bash_logout
L'opera di debugging di un processo non è generalmente argomento proponibile ad un sistemista non esperto, anche perchè spesso riguardano problemi sul lato applicativo che vanno affrontati direttamente dallo sviluppatore.
In ogni caso, nella vita di ogni sysadm capita sistematicamente che dei servizi non partano o dei programmi non facciano quello che dovrebbero fare (non inchiodarsi, innanzitutto), oppure, più subdolamente, abbiano comportamenti erratici o problemi di prestazioni o di sopportazione di alti carichi.
Senza volersi addentrare in problematiche di debugging avanzato, si possono elencare alcuni strumenti a disposizione del sistemista per diagnosticare simili problemi:
Log
I log sono sempre la prima cosa da guardare perchè di solito contengono abbastanza informazioni da farci capire dove intervenire. Eventualmente analizzare syslog.conf
o le istruzioni e le configurazioni del singolo programma per capire dove vengono loggati i suoi messaggi e poi leggere i messaggi di errore sui log che ci interessano.
Debug
Quasi sempre è possibile lanciare un programma con diversi livelli di debug: aumentando la verbosità del debug (di solito registrato sul file di log) si aumenta la possibilità di capire cosa non funziona. Tipicamente il livello di debug può essere impostato come opzione da command line o nel file di configurazione.
Comandi di diagnostica
Unix mette a disposizione vari comandi utili per capire cosa fa un processo e come si comporta il sistema. SU Linux si possono comunemente trovare i seguenti tool:
strace
Traccia le chiamate di sistema e i segnali del programma specificato mentre lo esegue. Ovviamente va utilizzato solo per fini diagnostici, rallentando particolarmente la velocità di esecuzione. Spesso non è nemmeno necessario capire l'output di strace (invero piuttosto verboso e per molti incomprensibile), basta cercare righe dove si parla di errori e vengono indicati path o funzioni specifiche. Spesso un programma non funziona perchè non trova certi file (librerie ecc) o non ha i permessi adeguati sugli stessi, un grep ENOENT
sullo stdout di strace può evidenziare tutte le volte in cui si è cercato un file senza trovarlo (spesso questo non è un problema, in quanto un processo può trovare un file dopo averlo cercato senza successo in varie directory (con relativo messaggio di errore "ENOENT (No such file or directory)".
ldd
Stampa l'elenco delle librerie condivise utilizzate dal comando specificato
lsof
Elenca gli open file del sistema. Un open file può essere: un normale file, una directory, un file speciale a blocchi o caratteri, una librerira, una socket Internet, una socket Unix domain... E' utile per vedere le risorse utilizzate da un programma (e, per esempio, capire dove sta loggando).
Il processo di boot di una macchina Linux su sistemi x86 Intel compatibili comporta diverse fasi.
Conoscerle e saperle interpretare è fondamentale per il troubleshooting di problemi di avvio.
Il boot di un sistema Linux su un sistema x386 (su altri si possono essere differenze nelle prime fasi) prevede i seguenti stadi:
1- All'accensione il BIOS su ROM non volatile definisce l'ordine dei device da utilizzare per effettuare il boot.
2- Il BOOT SECTOR del primo device di boot contiene il codice (o i riferimenti su dove trovarlo) del loader che esegue il bootstrap del sistema operativo. Nel caso di Linux il più diffuso loader è LILO, una recente alternativa evoluta è GRUB.
3- Il loader lancia il caricamento del kernel di Linux, che si copia in memoria ed esegue i controlli e il riconoscimento dell'hardware presente.
4- A fine caricamento il kernel esegue il processo init, padre di tutti i processi, che gestisce il caricamento di tutti gli altri programmi da eseguire per completare il boot.
IL BIOS SU ROM
Ogni sistema Intel ha sulla motherboard un BIOS su ROM con cui gestire l'hardware del sistema.
All'avvio di un computer non c'è nulla in RAM e nessun programma predefinito da caricare.
Le istruzioni su come procedere sono nella memoria non volatile del BIOS, in cui, fra le impostazioni definibili dall'utente, c'e' la sequenza dei dispositivi da usare per il boot.
Nei BIOS più recenti è possibile bootare da floppy, cdrom, hard disk (potendo scegliere se dare precedenza a HD IDE o SCSI) e altri dispositivi quali Zip o scheda di rete.
Il BIOS cerca, nell'ordine configurato, il boot sector sui diversi dispositivi di boot previsti.
Gli hard disk hanno un boot sector per ogni partizione e un unico Master Boot Record (MBR) che è il primo boot sector dell'intero hard disk. Se si esegue il boot da un hard disk, è il codice contenuto nel MBR che viene eseguito.
IL LINUX LOADER
Esistono diversi loader che eseguono il bootstrap del sistema operativo per Linux:
Su sistemi Intel Based: LILO, GRUB, LOADLIN, SYSLINUX, BOOTLIN;
su sistemi Alpha: MILO;
su sistemi Sparc: SILO.
Tutti di fatto eseguono la stessa funzione, alcuni (loadlin e syslinux) sono programmi DOS che eseguono il kernel caricandolo da una partizione DOS, altri sono adattamenti di LILO che riguardano sistemi non basati su processori Intel.
Nella pagina LILO, GRUB e Master Boot Record vengono analizzati nel dettaglio:
LILO - Il più conosciuto e diffuso
GRUB - Un loader più recente e versatile di LILO in rapida diffusione.
IL KERNEL
Il kernel, invocato dal loader, viene caricato in memoria ed inizializza i vari device driver, visualizzando vari messaggi utili per capire e conoscere il proprio sistema.
I dettagli sull'avvio del kernel, il riconoscimento e l'inizializzazione dell'hardware sono riportati nel TOPIC dedicato.
INIT E I SUOI FIGLI
L'ultima operazione eseguita dal kernel alla fine del suo caricamento è il lancio del processo init, il padre di tutti i processi.
Da questo momento tutto il codice eseguito lavora in user space (in kernel space lavorano solo il kernel e i suoi moduli).
L'init, tramite il suo file di configurazione /etc/inittab, provvede a lanciare tutti i programmi che completano il processo di caricamento.
Init è il padre di tutti i processi, il suo ruolo principale consiste nel gestire il lancio di tutti i programmi necessari per rendere il sistema attivo creare i processi a partire dal suo file di configurazione: /etc/inittab.
Nell'inittab vengono definite le directory con gli script di avvio per i diversi runlevel (stati del sistema, in cui possono girare determinati programmi), il runlevel di default, altri script e comandi che vengono eseguiti al boot o in condizioni particolari.
Il primo script lanciato da inittab è (su RedHat Linux) /etc/rc.d/rc.sysinit: che esegue varie operazioni tra cui:
Impostazioni di alcuni path generali nella variabile $PATH; Configurazione dell'ambiente di rete;
Avvio swap per la memoria virtuale;
Impostazione del nome dell'host;
Check del filesystem root;
Check delle quote di spazio assegnate agli utenti, se previste;
Mount del filesystem root in modalità scrittura/lettura;
Preparazione del sistema per caricamento dei moduli;
Check delle dipendenze dei moduli;
Check di tutti i filesystem ed eventuali riparazioni;
Mount di tutti i filesystem;
Pulizia di file di supporto al boot e di processi non più attivi;
Umount dell'initrd;
Impostazione dell'orologio;
Attivazione dello swapping;
Inizializzazione delle porte seriali;
Caricamento Moduli;
Attivazione dei servizi del runlevel.
Durante la fase di file system check, se si trovano errori che non possono essere riparati automaticamente è possibile che il processo di boot si blocchi. In questo caso viene richiesta la password di root e si può da shell fare un file system check manuale. Verificare su quale partizione il kernel si è fermato e scrivere (si considera che la partizione sia /dev/hda5 e abbia ext2 come file system): fsck.ext2 /dev/hda5.
Rispondere SI a tutte le lugubri domande sulla correzione di file danneggiati.
Ogni sistema Unix gestisce con file e procedure diverse il processo di boot, ma tutti si basano su Init e il suo file di configurazione inittab
. Per cui basta analizzare questo file e capirne la logica per poter capire come viene caricato il sistema ed intervenire dove necessario in caso di problemi.
Unix è un sistema operativo multiuser che, oltre all'utente root, con privilegi di amministrazione, prevede utenti di sistema (usati per eseguire processi e demoni) e utenti umani che utilizzano e accedono in vario modo alla macchina.
La gestione (aggiunta, modifica, cambio password, cancellazione) degli utenti del sistema è tipicamente compito di root, che ha a disposizione su diversi sistemi Unix variegati programmi grafici o comandi testuali per queste operazioni.
I comandi più comuni e standard per gestire gli utenti sono:
useradd [opzioni] nomeutente
Aggiunge un utente al sistema. Prevede varie opzioni per definire impostazioni specifiche.
userdel [opzioni] nomeutente
Elimina un'utente. Su molti Unix questo comando non cancella la home directory dell'utente.
groupadd [opzioni] nomegruppo
Aggiunge un gruppo.
passwd [nomeutente]
Modifica la password. Tutti gli utenti, tranne root, possono cambiare solo la propria password.
Il file con l'elenco di tutti gli utenti è, su tutti i sistemi Linux, /etc/passwd
, qui ci sono informazioni sulla login dell'utente, la shell utilizzata, la posizione della sua home directory, dove l'utente può liberamente scrivere dati e documenti.
In tutti i Linux moderni, la password, criptata viene scritta nel file /etc/shadow
dove vengono mantenute altre informazioni relative alla gestione della stessa.
Per installare dei programmi su Linux esistono vari modi:
- compilare il sorgente, pratica che può essere complessa ma è utile in casi particolari;
- utilizzare pacchetti (packages) che contengono i programmi già compilati e pronti per l'uso, facilitando e standardizzando la gestione del software sul sistema.
I sistemi di package più comuni su Linux sono RPM e DEB.
I pacchetti .deb vengono usati nelle distribuzioni derivate da Debian, gli .rpm sono stati definiti da RedHat e risultano essere i più diffusi.
Slackware pacchettizza il suoi programmi con normali tar gzippati: .tgz.
Affrontiamo qui l'uso di RPM, Red Hat Package Manager, sottolineando che file .deb e, in parte, .tgz vengono gestiti con comandi diversi ma hanno una logica simile.
Un package costruito con RPM è un archivio di file e informazioni che può essere installato, rimosso, interrogato sul sistema.
RPM permette di installare programmi, già compilati, con una facilità e rapidità estrema sul proprio Linux (è paragonabile ad un unico setup.exe su Windows).
Si sottolinea che ogni distribuzione e anche ogni versione della stessa distribuzione richiede pacchetti dedicati, adatti per il proprio sistema: un RPM realizzato per RedHat 6.2, per esempio, difficilmente funzionerà su RedHat 7.2.
RPM gestisce automaticamente le "dependencies": se si prova ad installare un RPM che richiede librerie o programmi non presenti o non abbastanza aggiornati sul sistema, l'installazione fallisce e viene indicato quali file mancano.
Analogamente, se si prova a rimuovere un package che contiene file utilizzati da altri programmi, viene dato un messaggio di errore.
Gli RPM automaticamente distribuiscono i file di un pacchetto nelle directory giuste (logs in /var/log, file di configurazione in /etc/, binari in /usr/bin o /usr/sbin, script di startup in /etc/rc.d/init.d/ ecc.) e verificano la presenza di conflitti o installazioni più recenti.
La rimozione di un RPM non cancella mai nulla che non abbia installato. Se deve sostituire o cancellare un file di configurazione, per esempio, viene mantenuto il file esistente con il suffisso .rpmsave
.
Le opzioni più comuni per usare il comando rpm
per gestire file .rpm sono:
rpm -i [opzioni] pacchetto
Installa il pacchetto .rpm specificato.
rpm -U [opzioni] pacchetto
Aggiorna il pacchetto con una versione più recente.
rpm -e [opzioni] pacchetto
Disinstalla il pacchetto, rimuovendone i file dal sistema.
rpm -q [opzioni] [pacchetto]
Visualizza informazioni varie sul pacchetto (descrizione, file contenuti ecc.)
Le comuni distribuzioni Linux offrono svariati tool grafici per una semplice gestione dei pacchetti installati sul sistema. Di fatto questi programmi eseguono le stesse operazioni del comando rpm, ma sono più semplici ed immediate da usare.
La tendenza, sempre più diffusa, è quella di prevedere meccanismi di update automatizzato, per gestire il sempre alto numero di aggiornamenti (per sicurezza e bug fix) di programmi.
E' un principio analogo al Windows Update su sistemi Microsoft, ma si applica a tutti i programmi installati, e non solo al sistema operativo.
La suite di Openssh nasce dal gruppo (ma non solo) che sviluppa OpenBSD, ha come scopo la sostituzione di tutti quei comandi intrinsecamente pericolosi come telnet, rcp poiche' il traffico passa in chiaro (comprese le nostre preziosissime password) con comandi e tools che implementano protocolli criptati considerati sicuri come SSH protocol
versione 1.3, 1.5 e 2.0.
Lo sviluppo della suite e' gestita da due team, uno che si focalizza sullo sviluppo del codice in ambiente OpenBSD ed un secondo che si preoccupa del porting della suite su altri OS.
Anche se lo sforzo e' notevole (Updates,patchs non mancano di certo ed escono con una certa frequenza) molto spesso affiorano problemi di sicurezza non indiferrenti (Addirittura Troyan nei sorgenti) che richiedono un immediato patching. La suite di Openssh include:
ssh
Per la sostituzione di telnet e rlogin
scp
Per la sostituzione di rcp
sftp
Per la sostituzione di ftp
sshd
Il comando per lanciare un server ssh.
Inoltre sono fornite utility per la gestione delle chiavi pubbliche e private. (ssh-add ssh-keygen
...).
Di sicuro la sua portabilita', facilita' di installazione e l'innumerevoli features lo rendono il mezzo piu' utilizzato al mondo per aprire conessione in quelle reti non considerate trusted.
Ecco alcune features:
Open Source Project Il codice sorgente e' disponibile a tutti, con tutti i vantaggi del caso.
Free Licensing La suite openssh non ha una licenza ristrettiva e puo' essere utilizzata anche per scopi commerciali.
Strong Encryption Openssh utilizza algoritmi come 3DES e Blowfish per una miglior e sicura compressione dati.
X11 Forwarding (encrypt X Window System traffic) Permette la compressione del traffico di un remoto X windows, quindi possiamo esportare sul nostro display senza preoccuparci di una possibile intercettazione della nostra password
Port Forwarding (encrypted channels for legacy protocols) Ci permette di forwardare le connessioni TCP/IP standard su una macchina remota attraverso canali sicuri ovvero criptati. Ad esempio il POP si potrebbe rendere sicuro in questo modo.
Strong Authentication (Public Key, One-Time Password e Kerberos Authentication) Molteplici tipi di autentificazione robusti.
Alcuni processi devono essere eseguiti a determinati orari, un determinato numero di volte. Esempi di questi possono essere i processi di backup che vengono lanciati ogni notte, oppure un analizzatore di log che deve girare ogni minuto.
Questi processi devono girare un certo numero di volte oppure in determinati giorni; il resto del tempo essi stanno fermi fino a quando un utente non interagisce con essi e li richiama (con gli appositi comandi). Qui è dove il CRON si rende utile. Vi permette di programmare (o "schedulare", come si dice in gergo) l'esecuzione di un lavoro in qualsiasi momento desideriate, ogni minuto, ogni ora, giornalmente, mensilmente.
E' un sollievo sapere che ci sono vari programmi che stanno girando senza alcun bisogno della vostra supervisione.
Le Basi
Cron può essere fatto partire da rc
o da rc.local
e ritorna immediatamente al prompt, sicchè non c'é bisogno di lanciarlo in background. Cron ricerca il file /etc/crontab
per le voci (le cosiddette "entry") di sistema e /var/spool/cron
per le voci relative agli utenti che si trovano nel file /etc/passwd
. Tutte le voci ritrovate sono caricate in memoria.
Tutto ciò viene ripetuto ogni minuto appena cron "si sveglia" ed esegue diversi compiti:
a) ricerca le voci ed esegue i programmi che sono stati schedulati.
b) determina se il modtime (vale a dire la data e l'ora dell'ultima modifica) nella directory di cron è cambiato c) se il modtime nella directory cron è cambiato, cron ricerca tutti i file e ricarica i programmi che sono stati modificati.
Poiché cron cerca le modifiche ogni minuto, non è necessario farlo ripartire quando sono stati effettuati dei cambiamenti (editati) nei file nella directory cron.
Utilizzare crontab
Il "cron daemon" legge il file "crontab"; ogni utente può avere la propria versione di questo file, orientata agli specifici compiti che si vogliono eseguire. I flag associati con le applicazioni crontab specificano quando aprire crontab per avere la lista o per rimuovere e modificare compiti.
La sintassi per il programma crontab è la seguente:
crontab [-u user] file
crontab [-u user] -l -e -r
Questi parametri indicano:
-u
questa opzione comunica al sistema il nome dell'utente che "possiede" il file. Se l'opzione -u è omessa, il sistema deduce per default che state usando il vostro crontab personale.
Il comando switch user (su) può confondere il crontab, così se siete nello switch "su" assicuratevi di utilizzare l'opzione -u.
-l
questa opzione dice a crontab di elencare i file nello standard output, in poche parole visualizza il file.
-e
questa opzione dice a crontab di editare il file. Cron usa l'editor definito dalla variabile EDITOR o da VISUAL. Se nessuna di queste variabili è definita, parte in automatico l'editor "vi". Quando si esce dall'editor, è immediamente piazzato nella locazione corretta e viene aggiornato il campo data/ora.
-r
questa opzione rimuove il file crontab specificato, se nessun file viene specificato, rimuove il file crontab dell'utente.
Voci in Crontab
Solo 2 tipi di voci sono permesse nel crontab: i settaggi ambientali (Crontab Environmental settings) e i settaggi di comando (Crontab Command settings)
a) Crontab Environmental settings
I settaggi ambientali utilizzano la seguente forma:
nome = valore
Cron conosce già le diverse variabili ambientali. Per esempio, SHELL è settato a /bin/bash
.
Altre variabili ambientali, come LOGNAME e HOME, sono associate al possessore del file. SHELL e HOME posso essere sovrascritte nello script, mentre non è possibile farlo con LOGNAME. Se MAILTO è definito (e non è settato a " "), tale variabile è inserita in una riga nel file crontab, e spedisce ogni messaggio generato all'utente specificato in questo campo.
La seguente riga mostra MAILTO settato ad uno specifico utente (luca): # spedisce tutti gli output all'utente *luca* (non importa chi è il proprietario di questo crontab)
MAILTO=luca
b) Crontab Command settings
I settaggi comandi usano un formato standard: ogni riga inizia con cinque campi ora/data. Se è il crontab di sistema, il campo successivo è lo username associato con la voce. Il campo seguente sarà il comando da eseguire. Il comando verrà eseguito solo quando la data e l'ora corrente coincideranno con tutti i valori dei campi time/date del crontab. Nel paragrafo succ. vi è un esempio.
I campi disponibili per la data e l'ora sono i seguenti:
Campi | Valori ammessi
----------------
minuti | 0-59
ore | 0-23
giorno | 1-31
mese | 1-12
giorno della settimana | 0-7 (0 & 7 indicano la domenica)
Questi campi possono anche contenere un asterisco (*) invece di un numero. Un asterisco indica che ogni possibile valore è ammesso.
Dettagli
La righe seguenti mostrano il /etc/crontab installato per default nella RedHat 6.2:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/
# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly
Avete notato come crontab chiama i quattro diversi eventi?
Il primo è associato ad eventi orari (eseguiti nel primo minuto di ogni ora)
Il secondo è associato ad eventi giornalieri (eseguiti alle ore 4:02 di ogni giorno)
Il terzo è associato ad eventi settimanali (eseguiti alle 4:22 di ogni domenica)
L'ultimo è associato ad eventi mensili (eseguiti alle 4:42 nel primo giorno di ogni mese).
Qualcosa da ricordare:
Il sistema non va indietro e raccoglie i lavori cron, esso li esegue solo se la data e l'ora sono uguali alla voce nel file. Ad esempio se il computer è spento quando dovrebbe essere eseguito il cron, quel programma non viene più eseguito.
Permessi e divieti di accesso al servizio crontab
Ci sono due file che abilitano la root (solo la root dovrebbe avere il permesso di editare o creare questi file) per autorizzare o vietare l'utilizzo dei servizi crontab agli utenti; essi sono: /etc/cron.allow -- Questo file in genere non esiste, lo dovete creare. Ogni voce che piazzerete in questo file coprirà quella inserita in /etc/cron.deny. Se il file /etc/cron.allow
esiste, solo gli utenti specificati dentro posso usufruire del servizio crontab.
/etc/cron.deny
-- Questo file esiste per default. In esso, ci metterete lo username delle persone a cui vietate l'utilizzo del servizio crontab.
Molto spesso ci si ritrova a diagnosticare problemi, capire perchè una applicazione non parte o eseguire blandi compiti di reverse engineering sul funzionamento di parti del sistema.
La prima fonte da consultare per ogni operazione di troubleshooting sono i log, file di testo che tengono traccia di errori e particolari azioni eseguite dal sistema, come il cambiamento di una password, il login di un certo utente o il messaggio di errore di una applicazione.
I log del sistema vengono generalmente scritti in directory come /var/log
e var/adm
o dove definito nei file di configurazione dei singoli programmi.
In quasi tutti i sistemi Unix il demone syslogd si occupa della gestione dei log tramite il file di configurazione /etc/syslog.conf
.
Le recenti distribuzioni Linux utilizzano sysklogd, una versione evoluta di syslogd che gestisce anche il logging del kernel (tramite il demone klogd).
Sono inoltre disponibili versioni modificato o più sicure di syslog.
L'equivalente su Windows dei log Unix sono gli eventi.
Nelle versioni di Linux più recenti Inetd viene sostituito da un superdemone più versatile e sicuro: Xinetd.
A differenza del precedessore, xinetd:
- Limita o regola l'accesso a determinati servizi sia con un sistema proprio sia inglobando nella sua configurazione i TcpWrappers
- Offre un sistema di logging indipendente da syslog
- Permette di limitare l'accesso ai servizi in determinate ore della giornata
- Supporta il protocollo Ipv6
- Utilizza vari meccanismi che mitigano l'impatto di un attacco DOS.
La configurazione del demone e dei servizi può essere suddivisa in più file (non compatibili con /etc/inetd.conf).
Su RedHat si deve operare su:
/etc/xinetd.conf
File principale di configurazione del demone
/etc/xinetd.d/*
Directory che contiene i singoli file dei servizi offerti da xinetd
Ogni programma eseguito su un sistema è un processo, identificato con un suo PID. Quando un programma viene eseguito da una shell, assume anche un numero di job e può essere gestito all'interno della shell.
Le modalità fondamentali con cui si possono lanciare i job sono due: in foreground e in background.
Nella prima l'utente attende che l'esecuzione del suo processo termini prima di riottenere il prompt della shell.
Nella seconda invece il prompt viene restituito subito e il processo continua l'esecuzione. In questo modo l'utente può continuare a lavorare e quindi, volendo, potrebbe lanciare altri programmi in background.
Il segno & scritto alla fine del comando dice alla shell di eseguirlo in background e ridare subito il prompt.
Con CTRL-C si interrompe un processo.
Con CRTL-Z si mette in “pausa” un processo e si ritorna al prompt della shell.
La shell prevede una serie di comandi interni per gestire i job:
jobs: mostra i processi attivi in background lanciati da un certo utente. Il numero tra parentesi che viene restituito a video è il numero di, il “+” significa che è l’ultimo processo ad essere stato sospeso (fg senza parametri fa ripartire l’ultimo processo sospeso), l’altro numero è il PID.
bg: Esegue in background un processo precedentemente interrotto.
fg: Esegue un processo in primo piano.
Esistono inoltre vari comandi (file autonomi, non incorportati nella shell) utili per gestire i processi:
kill: Invia un segnale ad un processo attivo (normalmente utilizzato per fermare un processo).
nice [priority] [command]: E' un prefisso utilizzato per assegnare un certo livello di priorità al comando che si sta per eseguire. -20 vuol dire massima priorità, 19 è minima priorità.
nohup
ps: Visualizza un elenco dei processi in fase di esecuzione
pstree: Simile a ps ma mostra chiaramente le relazioni tra processi padre e processi figli.
top: Visualizza un elenco dei processi che sfruttano intensamente il processore e consumano molta memoria.
La shell permette di definire mediante l'uso di variabili alcuni parametri che influenzano il comportamento dei programmi che vengono eseguiti.
Si usa distinguere fra Variabili d'ambiente, generalmente indicate in MAIUSCOLO, che vengono passate ad ogni programma eseguito dalla shell e quindi costituiscono di fatto la definizione di un una serie di parametri globali, e variabili locali, che vengono create ed utilizzate solo all'interno di un programma (che può essere anche uno script shell) e che generalmente si indicano in minuscolo.
Di solito basta esportare una variabile locale per farla diventare d'ambiente.
Si identifica una variabile con il simbolo $.
Le variabili d'ambiente più importanti sono:
HOME il valore di questa variabile è quella della home-directory dell'utente
PATH l'elenco delle directory dove la shell, dopo l'inserimento di un comando, cerca il programma da eseguire
DISPLAY definisce lo schermo sul quale un programma X-Window aprirà le proprie finestre
TERM definisce le sequenze di comandi che saranno usate per comandare il terminale che si sta usando.
Con il comando printenv
o env
vengono visualizzate le variabili d'ambiente della propria shell.
La struttura delle directory in un sistema Linux ha molte caratteristiche comuni a quella di altri sistemi Unix.
Sotto vengono riportare le directory principale e più comuni su Unix diversi, altre directory possono avere nomi o funzionalità diverse in Unix diversi (e anche in distribuzioni Linux diverse).
/
Radice (root). La directory principale che contiene tutte le altre.
/root
Home dell'utente root, da non confondere con la root ( / ), che è la directory principale e non una directory che si chiama /root
/boot
Contiene tutte le immagini del kernel e file indispensabili al bootstrap del sistema
/etc
Contiene i file di configurazione del sistema e dei programmi installati
/home
Contiene le home directory degli utenti normali (tutti tranne l'utente root)
/usr
Contiene binari, documentazione, librerie e sorgenti della maggior parte dei programmi (e i sorgenti del kernel)
/var
Contiene tutti file che hanno informazioni dinamiche, che tendono a modificarsi con il tempo: log, file di pid e lock dei processi in esecuzione, directory di spool (stampa, mail...) ecc.
/proc
File system virtuale, generato in tempo reale dal kernel. Contiene, come se fossero file e directory, dati dinamici sul sistema e sui processi
/dev
Contiene file speciali, che corrispondono a dispositivi hardware o a funzionalità particolari. Tramite di essi si può accedere al relativo device hardware.
/sbin
Contiene comandi e programmi riservati a root ( altri comandi sono in /usr/sbin/
)
/bin
Contiene comandi e programmi base per tutti gli utenti (altri comandi sono in /usr/bin/
)
SWAP
Non è una directory ma una partizione speciale, utilizzata come memoria virtuale.
Su Unix sono disponibili svariati comandi che permettono la visualizzazione del contenuto di file di testo o binari.
Fare pratica con i principali è fondamentale per la normale attività sistemistica.
Tutti questi comandi hanno svariate opzioni e possibilità di eseguire operazioni anche complesse.
In genere si suggerisce di fare pratica con le funzionalità di base ed eventualmente usare le opzioni più evolute o rare in script shell o casi particolari.
cat
Visualizza il contenuto di un file di testo
tac
Fa esattamente la stessa cosa di cat, ma al contrario, visualizzando per prime le utile righe di un testo.
less
Visualizza il contenuto di un file testo, pagina per pagina
more
Come less, ma con meno funzioni
tail
Visualizza l'ultima parte di un file di testo
head
Visualizza la prima parte di un file di testo
file
Analizza e mostra il tipo di un file
strings
Visualizza stringhe di testo all'interno di un file binario
Per file system si intende l'astrazione (metodo e protocolli) con cui un sistema operativo organizza i file su un supporto fisico di memorizzazione ad accesso casuale (floppy, cdrom, memoria, hard disk...).
I sistemi operativi moderni tipicamente utilizzano un sistema gerarchico (diviso in directory e sottodirectory) e possono supportare nativamente uno o più diversi file system.
Linux grazie alla sua polivalenza permette di utilizzare quasi tutti i file system più diffusi, ma il suo file system "storico" è ext2.
Dal kernel 2.4.x è disponibile il supporto per un'evoluzione dell'ext2, l'ext3 che, oltre ad essere convertibile facilmente in ext2, ha il vantaggio di essere un journal file system (basato su un log di tutte le operazioni di scrittura su disco, che aumenta l'integrità e il controllo .
Prima di poter utilizzare un qualsiasi dispositivo con il proprio filesystem (es: CDROM, floppy, tape, condivisione di rete windows, directory nfs, partizione fat32 di un hard disk... ) questo deve essere formattato e montato in una subdirectory della root ( / ).
Una volta montato il filesystem risulta accessibile a programmi e utenti in modo trasparente e diventa parte integrante dell'albero delle directory sotto /.
Dopo l'uso il filesystem può essere smontato (operazione necessaria per espellere un CDROM o un floppy).
La directory su cui viene montato un filesystem può anche non essere vuota, ma nel momento in cui ci viene montato un file system, i dati ivi contenuti non sono più visibili fino a quando non si esegue l'umount.
La gestione di diversi file system all'interno dello stesso albero di directory (la root: /) permette l'astrazione dei device hardware da parte del sistema operativo: per i programmi e gli utenti che accedono a determinati file non è importante conoscere o sapere su che tipo di dispositivo risiedono e possono accedere e gestire tutti i file con gli stessi strumenti, a prescindere dall'hardware su cui sono registrati.
Tutti i sistemi Unix hanno una gestione standard dei permessi sui file, che rispecchia la natura di sistema operativo multiutente.
I permessi possono essere di lettura, scrittura e esecuzione e vengono differenziati sulla base della natura dell'utente rispetto al file o directory:
- utente proprietario owner del file
- gruppo proprietario owner group del file
- gli altri utenti others, che sono l'owner e non appartegono all'owner group.
Il permesso di esecuzione è necessario per poter accedere a delle directory e, ovviamente, permette l'esecuzione di file (script shell, perl, php, cgi; programmi binari compilati).
Per visualizzare i permessi di un file basta usare il comando ls -l
che per ogni file da un output simile a:
-rwxr-xr-- 1 mark admins 77266 Dec 13 17:18 /bin/command.sh
La prima colonna, composta da 10 caratteri, descrive i permessi sul file /bin/command.sh.
Il primo carattere (nell'esempio: -) identifica il tipo di file (directory, pipe, block o char device, symlink...);
I successivi 3 caratteri identificano i permessi in lettura/scrittura/esecuzione dell'owner di /bin/command.sh (in questo caso l'owner mark ha tutti i permessi sul file: rwx );
I successivi 3 identificano i permessi del gruppo owner di /bin/command.sh (in questo caso il gruppo admins ha permesso di lettura ed esecuzione sul file: r-x );
I successivi 3 identificano i permessi di tutti gli altri utenti del sistema (in questo caso hanno solo il permesso di lettura: r-- ).
Le successive colonne nell'output di ls -l indicano l'owner, il gruppo, la dimensione in byte, la data di ultima modifica e il nome del file.
Per modificare i permessi dei file si usa il comando chmod che usa una duplice sintassi per indicare i permessi:
read - lettura: Flag r in symbolic mode; Valore 4 in octal mode
write - scrittuta: Flag w in symbolic mode; Valore 2 in octal mode
execute - esecuzione: Flag x in symbolic mode; Valore 1 in octal mode
Su Unix esistono molteplici comandi per la ricerca di file, all'interno dell'albero delle directory. Si basano su principi diversi e si adattano a diversi usi.
find - Ricerca file contenuti nella directory indicata in base a svariati criteri, come il nome, la data di modifica, la dimensione ecc. Utile per molti scopi.
locate - Ricerca file che matchano un pattern specificato tramite un database che permette ricerche veloci e viene aggiornato col comando updatedb.
whereis - Visualizza i path di binari, sorgenti e manuali per un comando
which - Mostra la posizione di comandi eseguibili all'interno del proprio ambiente PATH.
whatis - Cerca la parola completa specificata all'interno del database whatis, contenente brevi descrizioni dei comandi del sistema. Il database viene creato con il comando makewhatis
apropos - Come whatis, ma esegue ricerche anche di parole parziali.
Su Unix esistono vari comandi per confrontare file fra loro e verificare se sono diversi:
diff - Permette di fare un confronto fra il contenuto di due file di testo. Visualizza con un formato proprio le differenze e viene ampiamente utilizzato per creare delle patch di sorgenti.
diff3 - Come diff ma eseguito su 3 file.
bdiff - Come diff, ma lavora su file che possono essere divisi in più parti e quindi avere dimensioni anche molto grandi.
cmp - Compara due file ed esce con exit status diversi a seconda del risultato.
comm - Visualizza le righe diverse e quelle uguali in due file specificati.
dircmp - Compara il contenuto di 2 directory
Come sempre è possibile utilizzare vari comandi Unix comuni in script per ottenere risultati simili di confronto di file, del loro contenuto e di directory
Molti comandi Unix sono utilizzati come filtri per modificare il testo in input e presentarlo con l'output voluto. Vediamo alcuni dei filtri più comuni e, in genere, i comandi Unix utili per manipolare testi:
grep - Seleziona in file o nello standard input le righe di testo che contengono il pattern specificato. Es: Tutti le righe che contengono la scritta "bash".
sed - E' un flessibile e sofisticato strumento per modificare l'input secondo varie regole e match
sort - Ordina le righe del testo in input secondo criteri vari
tr - Converte o rimuove caratteri all'interno di un testo
cut - Ritaglia colonne o campi da un file, visualizzandone solo la parte selezionata
wc - Conta il numero di righe o di caratteri in un file
VI (visual editor) è il più importante e diffuso programma di editing dei file nell'ambiente UNIX e LINUX, in quanto possiede delle funzionalità che se utilizzate a fondo ne fanno uno strumento incredibilmente potente.
Per procedere all'editazione di un file basta digitare il comando "vi" seguito, o dal nome di un file già esistente nel caso in cui lo si voglia modificare, oppure dal nome di un nuovo file nel caso lo si voglia creare.
Nel momento in cui si procede all'editazione di un testo nell'ultima riga vengono sempre visualizzate le informazioni sul file aperto, come il numero di righe e di caratteri, il resto dell'area è destinata all'immissione dei comandi.
Se le righe non sono sufficienti a coprire tutta la porzione dello schermo a disposizione ne resteranno di vuote contrassegnate dalla tipica "~".
Questo editor possiede 3 diverse modalità di funzionamento in cui si svolgono azioni differenti:
Modalità d'inserimento o di input
Questo tipo di modalità fa riferimento alle azioni che consentono di modificare e aggiungere del testo. Una volta editato un file si accede a questa modalità con vari comandi, tra cui il tasto "i" che inserisce i caratteri prima del punto in cui è posizionato il cursore o "a" che invece inserisce i caratteri dopo il punto in cui è posizionato il cursore.
Modalità di comando visiva
La modalità di comando visiva permette di utilizzare una serie particolare di comandi ed è quella attivata di default. All'interno di questa modalità i comandi inseriti si riferiscono alla riga su cui è posizionato il cursore. Per passare alla modalità visuale da quella di inserimento, è sufficiente premere il tasto Esc.
Modalità di comando due punti
La terza e ultima modalità è quella che consente di utilizzare i comandi del salvataggio o dell'uscita dal programma. Per utilizzare questa modalità ed i conseguenti comandi premere ":" seguiti dal comando. In questo caso il cursore viene posizionato sull'ultima riga.
Fin dalle prime (ma non le primissime) versioni di Unix è stata introdotta nella shell la possibilità di redirezionare l'output di programmi (i dati che generano) ad altri programmi e di compiere analoghe operazioni con l'input e i messaggi di errore.
Questa possibilità, essendo valida per tutti i programmi e applicabile a tutti i file e oggetti del file system, permette una flessibilità enorme ed è particolarmente utile in script shell.
La shell gestisce la comunicazione con ogni programma lanciato tramite 3 file descrittori:
- standard input (stdin - file descriptor 0)
E' il canale attraverso il quale il programma riceve i dati di ingresso, generalmente la tastiera.
- standard output (stdout - file descriptor 1)
E' il canale di uscita del risultato dell'elaborazione del programma, di solito il video.
- standard error (stderr - file descriptor 2)
E' dove il programma stampa eventuali errori durante l'esecuzione, di solito il video.
Molti comandi UNIX assumono che l'ingresso dei dati avvenga (o possa avvenire) da standard input e l'uscita avvenga su standard output. E' possibile concatenare più programmi fra loro e fare in modo che lo standard output di uno diventi lo standard input di un altro. Per farlo si utilizza il carattere | chiamato pipe.
E' inoltre possibile redirezionare stdin, stdout e stderr su un file tramite gli operatori di redirezionamento:
> redirige lo standard output di un comando su un file o dispositivo
>> redirige l'output di un comando su un file o dispositivo ma se il file esiste già i dati vengono aggiunti alla fine del file. Se il file non esiste viene creato
< redirige lo standard input da un file o dispositivo
2> redirige lo standard error di un comando su un file o dispositivo
| operatore pipe, concatena standard output e standard input di due programmi
Come "uccidere" un utente collegato al sistema.
Con il comando who
o, più semplicemente w
è possibile conoscere gli utenti collegati al proprio sistema:
# w
22:35:33 up 5:17, 2 users, load average: 0.16, 0.33, 0.18
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root tty1 - 17:25 5:11m 0.02s 0.02s -bash
mozako :0 - 17:25 ?xdm? 5:52 0.00s -:0
mozako pts/1 ganja.fatalimpul 22:37 0.00s 0.01s 0.00s w
Prestando particolare attenzione al campo TTY e ponendo il caso di voler killare l'utente mozako sulla pts/1 è possibile farlo nel seguente modo:
# ps aux | grep pts/1
mozako 8742 0.0 0.3 5856 1740 ? S 22:38 0:00 sshd: mozako@pts/1
mozako 8743 0.0 0.3 3372 1920 pts/1 Ss 22:38 0:00 -bash
root 8754 0.1 0.3 2708 1576 pts/1 S 22:38 0:00 bash
root 8755 0.0 0.1 2412 844 pts/1 R+ 22:38 0:00 ps aux
root 8756 0.0 0.1 1692 608 pts/1 S+ 22:38 0:00 grep pts/1
Alla riga mozako 8743 0.0 0.3 3372 1920 pts/1 Ss 22:38 0:00 -bash abbiamo l'utente collegato alla pts/1, è possibile terminarlo come un normale processo: kill -9 8743