Capitolo 5

L'interfaccia utente (Shell)

In questo sistema operativo è disponibile un'unica interfaccia utente che nel seguito verrà chiamata per brevità Shell. La Shell si occupa di interpretare i comandi dati dall'utente e di avviare le parti del sistema che ne soddisfano le richieste; inoltre la shell si occupa di visualizzare il prompt, fornisce un breve messaggio se si digita un comando non riconosciuto e visualizza un piccolo logo all'avvio del sistema. Sui sistemi Unix normalmente esistono diverse shell che svolgono più o meno le stesse funzioni ma in modi diversi. Questo sistema, pur essendo dotato di un unica shell, possiede una struttura abbastanza flessibile (in particolare per la gestione degli interrupt dalle porte seriali) ed è in grado di supportare facilmente altre shell.

5.1 Realizzazione della Shell

La Shell ha una struttura molto articolata. Per prima cosa si deve notare che può essere attivata in più modalità. Alla partenza del sistema viene attivata in una modalità di inizializzazione chiamata "IOPX". In questo caso viene semplicemente stampata un'intestazione che in sostanza contiene un piccolo "logo". Se la Shell viene attivata in modalità prompt ("PROMPTPX") viene semplicemente visualizzato il prompt del sistema, cioè la stringa "Theos> ".
La terza modalità con cui viene avviata la Shell è chiamata "INTPX" ed è utilizzata per servire gli interrupt provenienti dalle porte seriali. In questo caso per prima cosa si verifica se è disponibile un comando completo, se non lo è la shell stampa l'eco sul monitor ed esce, altrimenti copia la stringa corrispondente al comando in una variabile locale e attiva la funzione ParseDetect che spezza la riga di comando nelle sue parti fondamentali, identifica il comando e lo avvia all'esecuzione.
Shell (p,cmid);
/* interprete di comandi del sistema */
{
    se in modalita' IOPX
        Stampa l'intestazione;
    altrimenti se in modalita' PROMPTPX
        Stampa il prompt;
    altrimenti se in modalita' INTPX {
        se c'e' un comando
            copia il puntatore al buffer;
        altrimenti se c'e' un comando parziale
            stampa l'eco;
        ParseDetect  /* riconosce la riga di comando */
    }
}

La funzione ParseDetect divide la riga di comando nelle sue parti fondamentali. Per prima cosa verifica se è presente il carattere & che distingue l'esecuzione in background da quella in foreground. Poi spezza la riga di comando in parole (separate da spazi). La prima parola è il comando, le parole successive se incominciano con il carattere `-' sono flag, altrimenti sono parametri. A questo punto confronta il comando con tutti i comandi noti al sistema (built in) e in caso affermativo avvia l'esecuzione di un processo ponendolo nella coda d'attesa. Altrimenti prova a vedere se il comando si riferisce ad un file eseguibile chiamando la funzione access e in caso affermativo ne avvia l'esecuzione. Altrimenti stampa una breve stringa che indica che il comando non è stato riconosciuto.
void ParseDetect()
/* spezza e riconosce una riga di comando */
{
    se la riga di comando termina con il carattere `&'
        setta il flag Background
    spezza la riga di comando in parole
    memorizza la prima parola come comando
    per tutte le parole dopo la prima {
        se la parola comincia con il carattere `-'
            aggiungila ai flag
        altrimenti 
            memorizza la parola come parametro
    }
    confronta il comando con tutti i comandi interni
    se coincide con un comando 
        CallData      /* Avvia un processo nella coda d'attesa */
    altrimenti 
        se access(comando,x) /* verifica permesso d'esecuzione */
            CallData  /* Avvia un processo nella coda d'attesa */
    altrimenti
        stampa che il comando e' sconosciuto
}

5.2 I comandi del Sistema Operativo

I comandi disponibili da shell sono riportati nella tabella 5.1. Alcuni comandi sono descritti nei capitoli dove si parla piú in dettaglio degli argomenti inerenti al comando. Tutti gli altri comandi sono illustrati di seguito.

Comando Descrizione
asm assemblatore
chmod modifica le proprietà di un file
cls cancella lo schermo
copy fa la copia di un file
compact cancella i file nel cestino
create crea un file di caratteri casuali
del cancella o mette nel cestino un file
dir visualizza i file presenti nella directory
download salva il contenuto del disco virtuale su HD
dump visualizza e modifica una locazione di memoria
edit edita un testo
format formatta il disco
help fornisce la lista dei comandi
kill termina l'esecuzione di un processo
logout termina la sessione
loop esegue un ciclo infinito
passwd modifica la password
ps mostra lo stato dei processi in corso
seeheap visualizza lo stato della memoria Heap
stat mostra una statistica degli errori di sistema
testheap permette di testare la memoria Heap
tiny avvia il compilatore tiny
type visualizza il contenuto di un file
upload carica il contenuto del disco virtuale
users mostra il nome degli utenti accreditati
version mostra la versione del sistema
Tabella 5.1: Lista comandi della shell

chmod Modifica i permessi d'accesso ad un file. I permessi possono essere cambiati o dal proprietario del file o dal superuser. Il superuser può cambiare i permessi di tutti i file tranne che quelli del file password.
La sintassi del comando da shell prevede che si pongano prima la lista dei permessi da aggiungere e da togliere e poi il nome del file su cui operare. I permessi vengono specificati dalle lettere `r' (lettura), `w' (scrittura) e `x' (esecuzione) e possono essere preceduti dal segno `-' se li si vuole togliere, comunque valgono sia per il proprietario che per tutti gli altri utenti. I permessi, in alternativa, possono essere specificati in modo più dettagliato mediante un numero ottale a due cifre, secondo le solite regole di Unix. Per maggiore chiarezza si consideri il seguente esempio:
Se da shell il proprietario del file ``filename'' digita:

          chmod 61 filename 
il sistema risponderà nel modo seguente:
          filename rw---x 
se a questo punto il proprietario digita:
          chmod +r -x filename 
questa volta il sistema risponde con:
          rw-r-- filename 

void chmod(pun,cmid)
/* comando builtin */ 
/* Cambia i permessi d'accesso a un file. */
{
    se i parametri non sono corretti
        mostra un piccolo aiuto ed esci
    riordina i parametri
    se il file non esiste o e' nel cestino esci
    se l'utente non e' il proprietario o il superuser esci
    aggiungi i permessi da mettere
    togli i permessi da levare
    visualizza i permessi risultanti
}
cls Questo comando si limita a cancellare lo schermo della porta da cui viene lanciato, gli unici caratteri che restano sono quelli del prompt.
copy fa la copia di un file su un file nuovo. Questo comando verifica che la sintassi sia corretta, che ci sia lo spazio sufficiente per il nuovo file, che il file sorgente esista, che non sia nel cestino e che sia consentita la lettura, che il file destinatario non esista né che sia nel cestino. Se tutte le condizioni sono soddisfatte, allora blocca il semaforo del disco e copia i blocchi di dati e le informazioni sull'indice.
COPY (cmid,pun)
/* comando builtin */ 
/* copia un file */
{
    se la sintassi e' errata
        stampa aiuto;
    altrimenti se spazio su disco insufficiente
        stampa evento;
    altrimenti se il file sorgente non esiste o e' nel cestino
        stampa evento;
    altrimenti se il file destinazione esiste o e' nel cestino
        stampa evento;
    altrimenti se accesso non consentito al file sorgente
        stampa evento;
    altrimenti {
        chiama down (DISK);
        copia i blocchi di dati;
        aggiorna l'indice;
        aggiorna i dati del disco;
        chiama up (DISK);
    }
}

create crea un nuovo file e lo riempie con caratteri casuali. Viene verificata la sintassi e la possibilità di scrivere un file e quindi vengono scritte lettere casuali per tutta la lunghezza del file.
CREATE (cmid,pun)
/* comando builtin */ 
/* crea un file contenente caratteri casuali */
{
    Se la sintassi e' errata
        stampa l'aiuto;
    altrimenti verifica se il file esiste gia'
    altrimenti verifica se lo spazio su disco e' sufficiente
    altrimenti {
        stampa l'intestazione;
        chiama down (DISK);
        per i da 0 fino alla dim. del file con passo 1 {
            scrivi lettere casuali sul disco;
        }
        aggiorna l'indice della directory
        chiama up (DISK);
    }
}

delete Opera in tre modi: con l'opzione -k il file viene cancellato definitivamente e subito dopo viene attivata dalla shell la routine che compatta il disco (compact). Con l'opzione -u recupera un file nel cestino. Se non viene specificata nessuna opzione, il file viene messo nel cestino. Questa funzione controlla che la sintassi sia corretta, che il file esista, che si abbia il permesso di scrittura. Quindi viene bloccato il semaforo del disco e viene marcato il flag di cancellazione.
DELETE (cmid,pun)
/* comando builtin */ 
/* cancella un file */
{
    se la sintassi e' errata
        stampa aiuto;
    altrimenti se il file non esiste
        stampa l'evento;
    altrimenti (!access(file,w))  /* file non scrivibile */
        stampa l'evento;
    altrimenti {
        chiama down (DISK);
        aggiorna il flag di cancellatura del file;
        chiama up (DISK);
    }
}

dir Fornisce la lista dei file presenti nella directory. Se come parametro viene dato un nome di un file, vengono stampate le informazioni solo su quel file (sempre che esista). Se viene usata l'opzione -a vengono fornite una serie di informazioni aggiuntive su ogni file (lunghezza e permessi d'accesso). Se viene usata l'opzione -w vengono visualizzati i file nel cestino.
DIR (cmid,pun)
/* comando builtin */ 
/* visualizza il contenuto della directory */
{
    se la sintassi e' errata
        stampa l'aiuto;
    altrimenti {
        stampa l'intestazione;
        se il file non e' specificato {
            stampa i file nel disco o nel cestino;
            stampa eventuali informazioni aggiuntive;
            stampa informazioni sul disco;
        }
        altrimenti se il file non esiste    
            stampa l'evento;
        altrimenti
            stampa le informazioni aggiuntive sul file;
        }
    }
}

format Inizializza il disco virtuale. Questa funzione se attivata in modalità di inizializzazione assegna il nome del disco. Se l'utente è il superuser o la sintassi è corretta, blocca la scrittura sul disco e inizializza il blocco zero specificando che non esiste nessun file.
FORMAT (cmid,pun)
/* comando builtin */ 
/* formatta il disco virtuale */
{
    se si e' in modalita' di inizializzazione
        assegna automaticamente il nome del disco;
    se l'utente != superuser
        stampa l'evento;
    altrimenti se sintassi errata
        stampa l'aiuto;
    altrimenti {
        chiama down(DISK);
        scrivi il blocco zero;
        chiama up(DISK);
        se in modalita' di inizializzazione
            stampa dati sul disco;
    }
}

help Visualizza una lista di comandi. Per quasi tutti i comandi è disponibile una descrizione più accurata digitando il nome del comando seguito dall'opzione -?.
init Riavvia la shell nella modalità di inizializzazione, ciò causa la visualizzazione del ``logo'' iniziale.
logout Termina la sessione dell'utente che ha digitato questo comando e attende che un altro utente avvii un'altra sessione. Ciò viene fatto utilizzando la funzione LOGIN, questa funzione viene eseguita in ogni caso su entrambe le porte all'avvio. Questa funzione verifica se si è in fase di inizializzazione, in caso negativo, attende che sia finito l'upload, verifica che il file password esista, ricerca il nome utente e la parola riservata nel file password e in caso di successo entra nel sistema (in modalità comando) e assegna un identificatore all'utente (UID).
LOGIN (cmid,pun)
/* comando builtin */ 
/* inizializza la sessione di lavoro di un utente */
{
    se si e' in modalita' di inizializzazione
        entra in modalita' login;
    altrimenti {
        cancella schermo;
        attendi che UPLD diventi up;
        se il file password non e' sul disco
        stampa l'evento;
        altrimenti {
            chiama down (DISK);
            cerca il nome utente nel file;
            se esiste {
                verifica la password
                se e' esatta {
                    stampa accesso consentito;
                    assegna il codice utente;
                    entra in modalita' comando;
                }
                altrimenti
                    stampa password errata;
            }
            altrimenti
                stampa utente inesistente;
            chiama up (DISK);
        }
    }
}

passwd Permette di modificare le parole d'accesso riservate contenute nel file password. Per prima cosa si verifica se esiste questo file, in caso affermativo si verifica se il servizio è stato richiesto dal superuser, in questo caso, a seconda di un parametro, è possibile inizializzare il file, inserire un utente, toglierlo, cambiare una password. Se invece il richiedente è un utente qualsiasi, è possibile modificare solo la propria password.
PASSWD (cmid,pun)
/* comando builtin */ 
/* gestione delle password */
{
    se esiste il file password {
        se l'utente e' il superuser {
            se si e' in modalita' di inizializzazione
                inizializza il file;
            altrimenti se si e' in modalita' di eliminazione
                elimina l'utente dal file;
            altrimenti se si e' in modalita' di inserimento
                inserisci nuovo utente con password;
            altrimenti se si e' in modalita' di modifica
                modifica la password;
        }
        altrimenti se la sintassi e' corretta
            modifica la password dell'utente attuale;
        altrimenti
            stampa aiuto;
    }
    altrimenti stampa file non esistente;
}

ps Visualizza tutti i Thread attivi. Per fare ciò viene interrogata la struttura di memorizzazione dei TCB dello schedulatore. Per ciascuna coda di priorità vengono esaminati tutti i TCB, per ognuno dei quali viene visualizzata una riga che contiene: la modalità d'esecuzione, la memoria utilizzata dai dati, lo Stack Pointer, il Program Counter, il PID, il TID, il puntatore allo Heap e il nome del processo a cui appartiene il Thread.
void PS()
/* comando builtin */
/* mostra la lista dei thread in esecuzione */
{
    per tutte le priorita' {
        p punta alla testa della coda
        finche' p != NULL {
            stampa le caratteristiche del TCB puntato da p
            p punta al prossimo TCB della coda
        }
    }
}

stat Visualizza una statistica degli errori che si sono verificati. Viene utilizzata la funzione PrintERROR in modalità di inizializzazione. Questa funzione viene utilizzata anche subito dopo che si è verificato un errore: viene identificato il tipo di errore e viene stampato un messaggio adeguato.
PrintERROR (p,cmid)
/* algoritmo di basso livello e comando builtin */ 
/* visualizza una stringa per ogni errore riconosciuto */
{
    se si e' in modalita' di inizializzazione
        stampa la lista degli errori con le relative statistiche
    altrimenti {
        verifica il tipo di errore;
        stampa il codice dell'errore;
        stampa la descrizione dell'errore;
    }
}

type visualizza sullo schermo il contenuto di un file di testo. Questa funzione verifica che la sintassi sia corretta, che il file esista, che non sia nel cestino e che sia consentito l'accesso in lettura. Se sono verificate queste condizioni viene aperto il file, viene letto a blocchi di 10 Kbyte e viene visualizzato ogni blocco. Con il parametro -h questo comando fornisce una breve intestazione con informazioni sul file.
TYPE (cmid,pun)
/* comando builtin */ 
/* stampa il contenuto di un file 
{
    Se la sintassi e' errata
        stampa l'aiuto;
    altrimenti verifica se il file non esiste
    altrimenti verifica se il file e' nel cestino
    altrimenti verifica se l'accesso non e' consentito in lettura
    altrimenti {
        se si vuole l'intestazione
        stampa l'intestazione;
        apri il file
        finche' il file non e' finito {
            leggi un blocco del file;
            stampa il contenuto blocco
        }
        chiudi il file
    }
}

upload Carica il contenuto del disco virtuale prelevandolo dal disco rigido presente sulla scheda master. Ciò è possibile perché sulla master è sempre attivo in background un processo che verifica continuamente il valore di una determinata locazione della memoria sulla scheda slave, se questo valore è 1 esegue l'upload, se è 2 esegue l'operazione inversa (download), altrimenti non fa niente. Quindi la funzione upload non fa altro che verificare i parametri, preparare il nome del file da cui prelevare i dati, bloccare il disco con un paio di semafori e porre ad uno la variabile di upload.
UPLOAD (cmid,pun)
/* comando builtin */ 
/* carica il disco virtuale */
{
    se in modalita' di inizializzazione
        prepara le variabili di comunicazione;
    se la sintassi e' errata
        stampa aiuto;
    altrimenti {
        se non viene specificato nomefile
            nomefile diventa "theos";
        chiama down (DISK);
        chiama down (UPLD);
        upload diventa 1;
        attendi che upload sia 0;
        chiama up (UPLD);
        chiama up (DISK);
    }
}

download svolge l'operazione inversa all'upload: memorizza il contenuto di tutto il disco virtuale su un file contenuto nel disco rigido della scheda master. Lo pseudocodice è perfettamente uguale a quello della upload tranne che per il fatto che la variabile globale upload viene posto a 2 invece che ad 1.
users fornisce la lista degli utenti accreditati. Questa funzione verifica la sintassi e la presenza del file password. In caso affermativo legge e visualizza il nome di tutti gli utenti accreditati in quel file.
USERS (cmid,pun)
/* comando builtin */ 
/* visualizza gli utenti accreditati */
{
    se la sintassi e' errata
        stampa aiuto;
    altrimenti se il file password non esiste
        stampa l'evento;
    altrimenti {
        stampa intestazione;
        scansiona il file stampando il nome ed il codice;
    }
}

version Visualizza la versione di Theos e il nome degli autori.


[Home] Back to Lucio's Home page.