Warning:  Undefined array key "view" in /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php on line 2
Warning:  Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php:2) in /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php on line 47
Warning:  Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php:2) in /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php on line 48
Warning:  Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php:2) in /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php on line 49
Warning:  Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php:2) in /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php on line 50
Warning:  Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php:2) in /var/www/html/wp-content/uploads/classes/so/1920/lab-homeworks/index.php on line 51
/*
    Homework n.5
    Estendere l'esempio 'nanoshell.c' ad una shell piu' realistica in cui
    si possono:
    - passare argomenti al comando invocato (per semplicita', assumiamo
    che questi non contengano spazi);
    - usare la redirezione dei canali di input/output/error;
    - mandare un comando in esecuzione in background (con la '&' finale).
    Esempi di invocazione che la shell dovrebbe supportare sono:
    $ cal 3 2015
    $ cp /etc/passwd /etc/hosts /tmp
    $ cat /tmp/passwd
    $ cat filechenonesiste 2>/dev/null
    $ ls -R /etc/ &
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define LEN_BUFFER 2048
#define DELIM   " "
#define MAX_ARGS 30
#define STDIN 0
#define STDOUT 1
#define STDERR 2
int main(int argc, char *argv[]) {
    char commandline[LEN_BUFFER];
    int pid, len, i, fd;
    char *token;
    char *args[MAX_ARGS];
    char bckg_exec;
    char *path_stdout, *path_stdin, *path_stderr;
    while (1) {
        printf("> ");
        fgets(commandline, LEN_BUFFER, stdin);
        len = strlen(commandline);
        if ( commandline[len-1] == '\n')
            commandline[len-1] = '\0';
        if ((strcmp(commandline, "exit") == 0) || (strcmp(commandline, "quit") == 0))
            break;
        if ((token = strtok(commandline, DELIM)) == NULL) {
            fprintf(stderr, "la riga di comando sembra malformata!\n");
            continue;
        }
        i = 0;
        bckg_exec = 0;
        path_stdout = path_stdin = path_stderr = NULL;
        do {
            /* controlla se si tratta del simbolo '&' che indica una esecuzione
               in background del comando  */
            if ((strlen(token) == 1) && token[0] == '&') {
                bckg_exec = 1;
                continue;
            }
            /* controlla se si tratta di una redirezione dei canali */
            if (token[0] == '<') {
                if (path_stdin == NULL) {
                    path_stdin = strdup(token+1);
                    if (!access(path_stdin, R_OK)) {
                        fprintf(stderr, "impossibile accedere in lettura al file specificato come standard input!\n");
                        free(path_stdin);
                        continue;
                    }
                } else {
                    fprintf(stderr, "doppia redirezione dello standard input!\n");
                    continue;
                }
                continue;
                /* TO FIX: sintassi inesatta, qui implementa '>2' piuttosto che '2>' */
            } else if (token[0] == '>') {
                if (token[1] == '2') {
                    if (path_stderr == NULL) {
                        path_stderr = strdup(token+2);
                    } else {
                        fprintf(stderr, "doppia redirezione dello standard error!\n");
                        continue;
                    }
                } else {
                    if (path_stdout == NULL) {
                        path_stdout = strdup(token+1);
                    } else {
                        fprintf(stderr, "doppia redirezione dello standard output!\n");
                        continue;
                    }
                }
                continue;
            }
            args[i++] = strdup(token);
        } while ((token = strtok(NULL, DELIM)) != NULL);
        args[i] = NULL;
        pid = fork();
        if ( pid == -1 ) {
            perror("fork");
            exit(1);
        }
        if ( pid == 0 ) {
            /* applica l'eventuale redirezione dei canali nel figlio */
            if (path_stdin != NULL) {
                fd = open(path_stdin, O_RDONLY);
                close(STDIN);
                dup(fd);
            }
            if (path_stderr != NULL) {
                fd = open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC, 0666);
                close(STDERR);
                dup(fd);
            }
            if (path_stdout != NULL) {
                fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC, 0666);
                close(STDOUT);
                dup(fd);
            }
            execvp(args[0], args);
            fprintf(stderr, "Errore nell'esecuzione di '%s'\n", args[0]);
            exit (2);
        } else if (!bckg_exec)
            wait(NULL);
        /* libero la memoria allocata dinamicamente nel padre */
        if (path_stdin != NULL) free(path_stdin);
        if (path_stderr != NULL) free(path_stderr);
        if (path_stdout != NULL) free(path_stdout);
        i = 0;
        while (args[i] != NULL)
            free(args[i++]);
    }
    exit(0);
}