/* Soluzione della Prova d'esame dell'11 Marzo 2008 - Parte C */ #include #include #include #include #include #include #include typedef int pipe_t[2]; int main(int argc, char **argv) { /* -------- Variabili locali ---------- */ int pid; /* process identifier per le fork() */ int N; /* numero di file passati sulla riga di comando (uguale al numero di stringhe) */ int rc; /* return value che il figlio passa al padre alla fine */ int status; /* variabile di stato per la wait */ pipe_t *piped; /* array dinamico di pipe descriptors */ int i, j; /* indici per i cicli */ char stringa[12]; /* variabile dove il figlio/padre mette la sua stringa TROVATA/NON TROVATA: riserviamo 12 caratteri che servono per la stringa piu' lunga piu' il terminatore di stringa! */ /* ------------------------------------ */ /* Controllo sul numero di parametri */ if ( (argc < 3) /* Meno di due parametri */ || ((argc-1)%2) /* In numero dispari*/) { printf("Errore nel numero dei parametri: devono essere in numero pari!\n"); exit(1); } /* Calcoliamo il numero di file/stringhe passate */ N = (argc - 1)/2; /* Allocazione dell'array di N pipe descriptors*/ piped = (pipe_t *) malloc (N*sizeof(pipe_t)); if (piped == NULL) { printf("Errore nella allocazione della memoria"); exit(2); } /* Creazione delle N pipe padre-figli */ for (i=0; i < N; i++) { if(pipe(piped[i]) < 0) { printf("Errore nella creazione della pipe"); exit(3); } } /* Ciclo di generazione dei figli */ for (i=0; i < N; i++) { if ( (pid = fork()) < 0) { printf("Errore nella fork."); exit(4); } if (pid == 0) /* codice del figlio */ { /* Chiusura dei lati non utilizzati delle pipe */ for (j=0; j < N; j++) { close(piped[j][0]); if (j!=i) close(piped[j][1]); } /* Creazione del processo nipote */ if ( (pid = fork()) < 0) { printf("Errore nella fork."); exit(4); } if (pid == 0) /* codice del nipote */ { /* Chiusura dell'unico lato di pipe rimasto aperto: il nipote non usa le pipe! */ close(piped[i][1]); printf("Nipote %d cerca nel file %s la stringa %s\n", getpid(), argv[i+1], argv[i+N+1]); /* Ridirezione dello standard output su /dev/null (per evitare messaggi di grep a video)*/ close(1); open("/dev/null", O_WRONLY); /* Il nipote diventa il comando grep */ execl("/bin/grep", "grep", argv[i+N+1], argv[i+1], (char *)0); /* attenzione all'ordine dei parametri nella esecuzione della grep: prima stringa e poi file e quindi terminatore della lista. Il file si trova usando l'indice i incrementato di 1 (cioe' per il primo processo i=0 il file e' argv[1]), mentre la stringa la si trova usando l'indice i incrementato di N e di 1 (cioe' per il primo processo i=0 la stringa file e' argv[N+1]) */ /* Non si dovrebbe mai tornare qui!!*/ exit(1); /* torno un valore diverso da zero per indicare insuccesso*/ } /* codice del figlio */ printf("Sono il processo figlio di indice %d e pid %d\n", i, getpid()); /* Aspetto la fine del nipote/grep */ wait(&status); if ((status & 0xFF) != 0) { printf("Nipote terminato in modo involontario\n"); /* si decide di mandare la stringa NON TROVATA al pafre e tornare il valore 1 */ strcpy(stringa, "NON TROVATA"); rc = 1; } else { /* corrrezione volontaria */ /* recupero il suo codice di ritorno */ rc = (status >> 8) & 0xFF; if (rc == 0) /* stringa trovata */ strcpy(stringa, "TROVATA"); else strcpy(stringa, "NON TROVATA"); } /* comunico la stringa al padre: la lunghezza deve essere quella massima. */ write(piped[i][1], stringa, sizeof(stringa)); exit(rc); /* fine codice del figlio */ } } /* Codice del padre */ for (i=0; i < N; i++) close(piped[i][1]); /* Il padre recupera le informazioni dai figli in ordine di indice */ for (i=0; i < N; i++) { /* il padre recupera al massimo 12 caratteri dalla pipe che comprendono sempre la stringa inviata dal figlio e il terminatore */ read(piped[i][0], stringa, sizeof(stringa)); printf("Il figlio di indice %d ha analizzato il file %s, cercando la stringa %s ed ha " "ritornato il seguente messaggio: %s\n", i, argv[i+1], argv[i+N+1], stringa); } /* Il padre aspetta i figli in ordine di indice */ for (i=0; i < N; i++) { pid = wait(&status); if ((status & 0xFF) != 0) printf("Figlio terminato in modo involontario\n"); else printf("Il figlio con pid=%d ha ritornato %d\n", pid, (int)((status >> 8) & 0xFF)); } }