/*
* ush: ush.c
*
* Progetto di Laboratorio di Sistemi Operativi
*
* Autore: Antonio Ospite 408/244
*
* Versione: 0.1
* Data: 07/06/2001
*
* Versione: 0.2
* Data: 28/07/2002
*/
#include "ush.h"
static void sig_chld (int);
int
main (int argc, char *argv[])
{
int myexit, len, len0, status;
char line[MAXLINE], *cmdbuf, *arg0;
pid_t pid;
/*
* modalità interattiva
*/
if (argc == 1)
{
myexit = 0;
make_joblist (&mylist);
/*
* Inizializazzione della shell
*/
init_shell ();
while (myexit != 1)
{
/*
* Se siamo superutenti il prompt
* ci verra' presentato con il
* carattere '#', altrimenti con '$'
*/
printf ("ush%c ", (getuid () == 0 ? '#' : '$'));
/*
* lettura comando
*/
fgets (line, MAXLINE, stdin);
/*
* lunghezza della riga di comando
*/
len = strlen (line);
/*
* Poichè fgets() non elimina
* lo '\n' finale, ci pensiamo noi
*/
line[len - 1] = 0;
/*
* Allocazione della stringa di comando
*/
cmdbuf = malloc (len);
strncpy (cmdbuf, line, len);
/*
* identificazione del primo argomento della riga di comando
*/
len0 = 0;
len0 = strcspn (cmdbuf, " ");
arg0 = malloc (len0);
strncpy (arg0, cmdbuf, len0);
arg0[len0] = 0;
/*
* Esecuzione di un semplice
* parsing della stringa di comando
* con analisi del primo argomento della
* riga di comando
*/
/*
* la riga di comando e' '\n' non si fa nulla
*/
if (len == 1);
/*
* cambio la working directory
*/
else if (strcmp (arg0, "cd") == 0)
chdir (cmdbuf + 3);
else if (strcmp (arg0, "exit") == 0)
myexit = 1;
else if (strcmp (arg0, "myjobs") == 0)
printlist (&mylist);
else if (strcmp (arg0, "fg") == 0)
{
pid = atoi (cmdbuf + 3);
put_job_in_fg (pid);
}
else if (strcmp (arg0, "back") == 0)
exec_bg_job (cmdbuf);
/*
* la riga di comando non contiene comandi interni alla shell
*/
else
{
/*
* se la riga di comando e' una pipeline la si gestisce
* oppurtunamente
*/
if (strchr (cmdbuf, ',') != NULL)
execpipe (cmdbuf);
/*
* la riga di comando non e' una pipeline
*/
else
exec_fg_job (cmdbuf);
free (arg0);
}
}
exit (0);
}
/*
* fine modalità interattiva
*/
/*
* opzioni della shell
*/
else if (argc > 1)
{
/*
* Parsing delle opzioni
*/
if (strcmp (argv[1], "--help") == 0 || strcmp (argv[1], "-h") == 0)
{
printf ("\noptions:\n");
printf ("\t-h, --help this help\n");
printf ("\t-v, --version version number\n");
}
else if (strcmp (argv[1], "--version") == 0
|| strcmp (argv[1], "-v") == 0)
printf ("%s version %s\n", *argv, VERSION);
else
printf ("Opzione sconosciuta.\n");
exit (0);
}
/*
* fine opzioni
*/
exit (0);
}
void
static init_shell ()
{
pid_t shell_pgid;
/*
* Ignoriamo i segnali che potrebbero terminare la shell
*/
signal (SIGINT, SIG_IGN);
signal (SIGQUIT, SIG_IGN);
signal (SIGTSTP, SIG_IGN);
signal (SIGTTIN, SIG_IGN);
signal (SIGTTOU, SIG_IGN);
signal (SIGCHLD, sig_chld);
/*
* Creazione di un nuovo gruppo di processi
*/
shell_pgid = getpid ();
if (setpgid (shell_pgid, shell_pgid) < 0)
err_quit ("Impossibile creare un nuovo gruppo di processi");
/*
* Otteniamo il terminale di controllo
*/
tcsetpgrp (STDIN_FILENO, shell_pgid);
}
static void
exec_fg_job (char *cmdbuf)
{
int status;
pid_t pid;
/*
* Generazione di un processo figlio
* con gli opportuni controlli di errore
*/
if ((pid = fork ()) < 0)
err_quit ("Errore di fork");
if (pid == 0)
launch_process (cmdbuf, getppid (), FOREGROUND);
/*
* Il genitore attende che il figlio
* termini la sua esecuzione
*/
if (pid > 0)
add_job_to_list (&mylist, pid, cmdbuf, "running");
if (waitpid (pid, &status, WUNTRACED) < 0)
err_quit ("Errore di waitpid");
if (WIFEXITED (status))
rm_job_from_list (&mylist, pid);
if (WIFSTOPPED (status))
{
printf ("\nProcesso con ID %d stoppato\n", pid);
change_job_status (&mylist, pid, "stopped");
}
if (WIFSIGNALED (status))
{
rm_job_from_list (&mylist, pid);
printf ("Processo con ID %d terminato per un segnale (%s)\n", pid,
sys_siglist[WTERMSIG (status)]);
}
}
static void
exec_bg_job (char *cmdbuf)
{
int status;
pid_t pid;
if ((pid = fork ()) < 0)
err_quit ("Errore di fork");
if (pid == 0)
launch_process (cmdbuf + 5, 0, BACKGROUND);
if (pid > 0)
add_job_to_list (&mylist, pid, cmdbuf + 5, "running");
if (waitpid (pid, &status, WNOHANG) < 0)
err_quit ("Errore di waitpid");
}
static void
launch_process (char *command, pid_t pgid, int foreground)
{
pid_t pid = getpid ();
/*
* Creazione di un nuovo gruppo di processi ed eventuale
* assegnazione del terminale di controllo al nuovo gruppo di processi
*/
if (pgid == 0)
pgid = pid;
setpgid (pid, pgid);
if (foreground == 1)
tcsetpgrp (STDIN_FILENO, pgid);
/*
* Si ripristina l'handling dei segnali
*/
signal (SIGINT, SIG_DFL);
signal (SIGQUIT, SIG_DFL);
signal (SIGTSTP, SIG_DFL);
signal (SIGTTIN, SIG_DFL);
signal (SIGTTOU, SIG_DFL);
signal (SIGCHLD, SIG_DFL);
/*
* Esecuzione del nuovo processo
*/
execl ("/bin/sh", "sh", "-c", command, (char *) 0);
/*
* Il codice che segue viene eseguito solo nel caso in cui
* la chiamata alla exec() fallisca
*/
err_quit ("Errore di exec");
}
static void
put_job_in_fg (pid_t pid)
{
int status;
if (has_job_status (&mylist, pid, "stopped") == 0)
{
if (kill (pid, SIGCONT) < 0)
{
perror ("Errore !");
return;
}
change_job_status (&mylist, pid, "running");
if (waitpid (pid, &status, WUNTRACED) < 0)
perror ("Errore di waitpid (fg)");
if (WIFEXITED (status))
{
rm_job_from_list (&mylist, pid);
printf ("Processo con ID %d terminato con successo\n", pid);
}
if (WIFSTOPPED (status))
{
printf ("\nProcesso con ID %d stoppato\n", pid);
change_job_status (&mylist, pid, "stopped");
}
if (WIFSIGNALED (status))
{
rm_job_from_list (&mylist, pid);
printf ("Processo con ID %d terminato per un segnale (%s)\n", pid,
sys_siglist[WTERMSIG (status)]);
}
}
else
printf ("il processo con ID %d non e\' in stato di STOP.\n", pid);
}
static void
sig_chld (int signo)
{
pid_t pid;
int status;
pid = waitpid (-1, &status, WNOHANG | WUNTRACED);
if (pid > 0)
if (WIFEXITED (status))
rm_job_from_list (&mylist, pid);
else if (WIFSTOPPED (status))
{
printf ("\nProcesso con ID %d stoppato\n", pid);
change_job_status (&mylist, pid, "stopped");
}
else if (WIFSIGNALED (status))
{
rm_job_from_list (&mylist, pid);
printf ("Processo con ID %d terminato per un segnale (%s)\n",
pid, sys_siglist[WTERMSIG (status)]);
}
return;
}
syntax highlighted by Code2HTML, v. 0.9.1