Soluzione esercitazione 5
[
testo esercitazione ]
Esercizio 1
#include <stdio.h> // fgets, printf, puts
#include <sys/wait.h> // wait
#include <unistd.h> // fork, execvp
#include <string.h> // strtok, strcpy, strrchr
#define MAX_LINE_SIZE 1024 // massima lunghezza riga di comando
#define MAX_NUM_ARGS 64 // massimo numero di token sulla riga di comando
#define PROMPT "SC1> " // prompt dei comandi
// ---------------------------------------------------------------------
// parse_cmd_line
// ---------------------------------------------------------------------
// estrae argomenti dalla riga di comando
// parametri:
// - cmd_line: [input] stringa di input contenente la riga di comando
// - tok_buf: [output] array in cui scrivere i token della riga di comando
// - tok_num_ptr: [output] puntatore a buffer in cui scrivere numero di token in tok_buf
void parse_cmd_line
(char cmd_line
[MAX_LINE_SIZE
],
char tok_buf
[MAX_NUM_ARGS
][MAX_LINE_SIZE
],
unsigned* tok_num_ptr
) {
unsigned tok_num =
0;
// numero token estratti da cmd_line
char buf
[MAX_LINE_SIZE
];
// buffer per non modificare cmd_line passata
strcpy
(buf, cmd_line
);
// copia cmd_line: strtok fa side-effect
const char* delim =
" \n\t";
// delimitatori tokenizzazione
char* token = strtok
(buf, delim
);
// tokenizza buffer
while (token !=
NULL) {
strcpy
(tok_buf
[tok_num
], token
);
// copia token corrente in tok_buf
token = strtok
(NULL, delim
);
// estrae token successivo
tok_num++;
}
*tok_num_ptr = tok_num;
// passa numero token estratti al chiamante
}
// ---------------------------------------------------------------------
// do_internal_cmd
// ---------------------------------------------------------------------
// prova ad eseguire comando interno
// parametri:
// - tok_buf: [input] array di token della riga di comando
// - tok_num: [input] numero di token in tok_buf
// restituisce:
// -1 se quit
// 0 se non e' un comando interno
// 1 se e' un comando interno
int do_internal_cmd
(char tok_buf
[MAX_NUM_ARGS
][MAX_LINE_SIZE
],
unsigned tok_num
) {
if (strcmp
(tok_buf
[0],
"quit") ==
0) return -1;
// altri comandi interni qui...
// if (strcmp(tok_buf[0], "miocomando") {
// do_mio_comando_interno(tok_buf, tok_num); // esegue cmd interno
// return 1; // cmd eseguito
// }
return 0;
}
// ---------------------------------------------------------------------
// _print_tok_buf
// ---------------------------------------------------------------------
// stampa token buffer (per scopi di debugging)
static void _print_tok_buf
(char tok_buf
[MAX_NUM_ARGS
][MAX_LINE_SIZE
],
unsigned tok_num
) {
int i;
printf("--- tok_buf [len=%u]\n", tok_num
);
for (i=
0; i<tok_num; i++
) printf("%s\n", tok_buf
[i
]);
printf("---\n");
}
// ---------------------------------------------------------------------
// make_argv
// ---------------------------------------------------------------------
// crea array di puntatori argv per comando esterno
// parametri:
// - argv: [output] buffer preallocato di puntatori agli argomenti del comando
// - tok_buf: [input] array di token della riga di comando
// - tok_num: [input] numero di token in tok_buf
void make_argv
(char* argv
[MAX_NUM_ARGS
+1],
char tok_buf
[MAX_NUM_ARGS
][MAX_LINE_SIZE
],
unsigned tok_num
) {
int i;
// estrae nome file dal pathname e lo fa puntare da argv[0]
char* s = strrchr
(tok_buf
[0],
'/');
if (s ==
NULL) argv
[0] = tok_buf
[0];
else argv
[0] = s
+1;
// inizializza argv[i] per i>0
for (i=
1; i<tok_num; i++
) argv
[i
] = tok_buf
[i
];
// aggiunge terminatore
argv
[tok_num
] =
NULL;
}
// ---------------------------------------------------------------------
// do_external_cmd
// ---------------------------------------------------------------------
// esegue comando esterno
// parametri:
// - tok_buf: [input] array di token della riga di comando
// - tok_num: [input] numero di token in tok_buf
void do_external_cmd
(char tok_buf
[MAX_NUM_ARGS
][MAX_LINE_SIZE
],
unsigned tok_num
) {
char* argv
[MAX_NUM_ARGS
+1];
// argv da passare a processo
make_argv
(argv, tok_buf, tok_num
);
// crea argv per processo
pid_t pid = fork
();
// genera nuovo processo
if (pid ==
-1) { // gestione errori
perror
("cannot spawn process");
return;
}
if (pid ==
0) { // processo figlio
execvp
(tok_buf
[0], argv
);
// carica programma
perror
("cannot exec program");
// loader fallisce
_exit
(1);
// termina proc figlio
}
wait
(NULL);
// shell attende term figlio
}
// ---------------------------------------------------------------------
// do_cmd_loop
// ---------------------------------------------------------------------
// esegue il ciclo di lettura/esecuzione dei comandi
void do_cmd_loop
() {
char cmd_line
[MAX_LINE_SIZE
];
// buffer per contenere riga di cmd
char tok_buf
[MAX_NUM_ARGS
][MAX_LINE_SIZE
];
// buffer token riga di comando
unsigned tok_num;
// numero token riga di comano
for (;;
) {
printf("%s", PROMPT
);
// stampa prompt
if (fgets
(cmd_line, MAX_LINE_SIZE, stdin
)==
NULL) // legge cmd line
break;
// esce se NULL
parse_cmd_line
(cmd_line, tok_buf, &tok_num
);
// estrae i token
if (tok_num ==
0) continue;
// ripete se riga vuota
int res = do_internal_cmd
(tok_buf, tok_num
);
// prova ad eseguire comando interno
if (res ==
0) do_external_cmd
(tok_buf, tok_num
);
// comando esterno
if (res ==
-1) break;
// esce su quit
}
}
// ---------------------------------------------------------------------
// main
// ---------------------------------------------------------------------
int main
() {
do_cmd_loop
();
puts
("\nsayonara.");
return 0;
}
Esercizio 2
Estendere la soluzione dell'esercizio 1 con le seguenti funzioni:
// ---------------------------------------------------------------------
// do_cd
// ---------------------------------------------------------------------
// esegue comando cd <path>
// parametri:
// - tok_buf: [input] array di token della riga di comando
// - tok_num: [input] numero di token in tok_buf
void do_cd(char tok_buf[MAX_NUM_ARGS][MAX_LINE_SIZE], unsigned tok_num) {
if (tok_num < 2) {
fprintf(stderr, "sintassi: cd <path>\n");
return;
}
int res = chdir(tok_buf[1]);
<