Advertisement
Derik_hacker

Untitled

Jun 6th, 2024
518
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.00 KB | None | 0 0
  1. /* Soluzione della Prova d'esame del 9 Giugno 2014 - Parte C */
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <fcntl.h>
  5. #include <sys/stat.h>
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <sys/wait.h>
  9.  
  10. typedef int pipe_t[2];
  11.  
  12. int main(int argc, char **argv)
  13. {
  14.    /* -------- Variabili locali ---------- */
  15.    int pid;             /* process identifier per le fork() */
  16.    int N;               /* numero di file passati sulla riga di comando (uguale al numero di figli) */
  17.    pipe_t *piped;           /* array dinamico di pipe descriptors per comunicazioni figli-padre  */
  18.    pipe_t p;                /* una sola pipe per ogni coppia figlio-nipote */
  19.    int i, j;                /* indici per i cicli */
  20.    char numero[11];         /* array di caratteri per memorizzare la stringa corrispondente al numero di righe: ci vogliono 10 char per rappresentare un intero di 16 bit e poi ci sara' il carattere di "a capo" (trasformato poi in terminatore di stringa!) */
  21.    int valore;              /* variabile che viene comunicata da ogni figlio al padre e che contiene la conversione della stringa in numero */
  22.    int ritorno;             /* variabile che viene ritornata da ogni figlio al padre e che contiene il ritorno del nipote */
  23.    long int somma = 0;          /* variabile usata dal padre per calcolare la somma di tutte le lunghezze comunicate dai figli */
  24.    int status;              /* variabile di stato per la wait */
  25.    /* ------------------------------------ */
  26.    
  27.     /* Controllo sul numero di parametri */
  28.     if (argc < 3) /* Meno di due parametri */  
  29.     {
  30.         printf("Errore nel numero dei parametri, dato che argc=%d: ci vogliono almeno due nomi di file\n", argc);
  31.         exit(1);
  32.     }
  33.  
  34.     /* Calcoliamo il numero di file passati e quindi di figli da creare */
  35.     N = argc - 1;
  36.    
  37.     /* Allocazione dell'array di N pipe descriptors*/
  38.     piped = (pipe_t *) malloc (N*sizeof(pipe_t));
  39.     if (piped == NULL)
  40.     {
  41.         printf("Errore nella allocazione della memoria\n");
  42.         exit(2);
  43.     }
  44.    
  45.     /* Creazione delle N pipe figli-padre */
  46.     for (i=0; i < N; i++)
  47.     {
  48.         if(pipe(piped[i]) < 0)
  49.         {
  50.             printf("Errore nella creazione della pipe\n");
  51.             exit(3);
  52.         }
  53.     }
  54.  
  55.     printf("DEBUG-Sono il processo padre con pid %d e sto per generare %d figli\n", getpid(), N);
  56.        
  57.     /* Ciclo di generazione dei figli */
  58.     for (i=0; i < N; i++)
  59.     {
  60.         if ( (pid = fork()) < 0)
  61.         {
  62.             printf("Errore nella fork\n");
  63.             exit(4);
  64.         }
  65.        
  66.         if (pid == 0)
  67.         {
  68.             /* codice del figlio */
  69.                         /* in caso di errore nel figlio o nel nipote, decidiamo di tornare -1 che verra' interpretato dal padre come 255 e quindi un valore non ammissibile! */
  70.             printf("DEBUG-Sono il processo figlio di indice %d e pid %d sto per creare il nipote che calcolera' il numero di linee del file %s\n", i, getpid(), argv[i+1]);
  71.             /* Chiusura delle pipe non usate nella comunicazione con il padre  */
  72.             for (j=0; j < N; j++)
  73.             {
  74.                 close(piped[j][0]);
  75.                 if (i != j) close(piped[j][1]);
  76.             }
  77.  
  78.             /* per prima cosa, creiamo la pipe di comunicazione fra nipote e figlio */
  79.             if(pipe(p) < 0)
  80.                     {  
  81.                             printf("Errore nella creazione della pipe\n");
  82.                                 exit(-1); /* si veda commento precedente */
  83.                     }
  84.  
  85.             if ( (pid = fork()) < 0)
  86.             {
  87.                 printf("Errore nella fork di creazione del nipote\n");
  88.                 exit(-1); /* si veda commento precedente */
  89.             }  
  90.             if (pid == 0)
  91.             {
  92.                 /* codice del nipote */
  93.                 printf("DEBUG-Sono il processo nipote del figlio di indice %d e pid %d sto per calcolare il numero di linee del file %s\n", i, getpid(), argv[i+1]);
  94.                 /* chiusura della pipe rimasta aperta di comunicazione fra figlio-padre che il nipote non usa */
  95.                 close(piped[i][1]);
  96.                 /* Ridirezione dello standard input: il file si trova usando l'indice i incrementato di 1 (cioe' per il primo processo i=0 il file e' argv[1])i; NOTA BENE: IN QUESTO CASO LA RIDIREZIONE ERA OBBLIGATORIA (anche se il testo parlava di comando) PER AVERE SULLO STANDARD OUTPUT SOLO LA STRINGA CORRISPONDENTE AL NUMERO! */
  97.                 close(0);
  98.                 if (open(argv[i+1], O_RDONLY) < 0)
  99.                 {
  100.                                     printf("Errore nella open del file %s\n", argv[i+1]);
  101.                                     exit(-1); /* si veda commento precedente */
  102.                             }
  103.                 /* ogni nipote deve simulare il piping dei comandi nei confronti del figlio/padre e quindi deve chiudere lo standard output e quindi usare la dup sul lato di scrittura della propria pipe */
  104.                 close(1);
  105.                 dup(p[1]);         
  106.                 /* ogni nipote adesso puo' chiudere entrambi i lati della pipe: il lato 0 non viene usato e il lato 1 viene usato tramite lo standard output */
  107.                 close(p[0]);
  108.                 close(p[1]);
  109.                 /* Ridirezione dello standard error su /dev/null (per evitare messaggi di errore a video): facoltativo! */
  110.                 close(2);
  111.                 open("/dev/null", O_WRONLY);
  112.                
  113.                 /* Il nipote diventa il comando wc -l */       
  114.                 execlp("wc", "wc", "-l", (char *)0);
  115.                 /* attenzione ai parametri nella esecuzione di wc: solo -l e terminatore della lista */
  116.                
  117.                 /* Non si dovrebbe mai tornare qui!!*/
  118.                 exit(-1); /* si veda commento precedente */
  119.             }
  120.             /* codice figlio */
  121.             /* ogni figlio deve chiudere il lato che non usa della pipe di comunicazione con il nipote */
  122.             close(p[1]);
  123.             /* adesso il figlio legge dalla pipe un carattere alla volta */
  124.             j=0;
  125.                 while (read(p[0], &(numero[j]), 1))
  126.             {
  127.                 j++;
  128.             }
  129.             /* all'uscita di questo ciclo while, nell'array numero ci saranno tutti i caratteri numerici corrispondenti al numero di linee del file e come ultimo carattere il terminatore di linea */
  130.             /* converto l'array di char in stringa sostituendo allo '\n' il terminatore di stringa, controllando pero' di avere letto in effetti qualcosa */
  131.             if (j!=0) /* se il figlio ha letto qualcosa */
  132.             {
  133.                 numero[j-1]='\0';
  134.                 /* convertiamo l'array di char in numero che bisogna comunicare al padre */
  135.                 valore=atoi(numero);
  136.             }
  137.             else
  138.             {       /* questo e' il caso che il nipote sia incorso in un errore e che quindi non abbia eseguito il wc -l */
  139.                                 valore=0;   /* se il figlio non ha letto nulla, inviamo 0 */
  140.                         }
  141.  
  142.             /* il figlio comunica al padre */
  143.             write(piped[i][1], &valore, sizeof(valore));
  144.  
  145.             /* il figlio deve aspettare il nipote per restituire il valore al padre */
  146.             /* se il nipote e' terminato in modo anomalo decidiamo di tornare -1 e verra' interpretato come 255 e quindi segnalando questo problema al padre */
  147.             ritorno=-1;
  148.             if ((pid = wait(&status)) < 0)
  149.                 printf("Errore in wait\n");
  150.             if ((status & 0xFF) != 0)
  151.                     printf("Nipote con pid %d terminato in modo anomalo\n", pid);
  152.                 else
  153.                 /* stampa non richiesta: SOLO DEBUGGING */
  154.                 printf("DEBUG-Il nipote con pid=%d ha ritornato %d\n", pid, ritorno=(int)((status >> 8) & 0xFF));
  155.             exit(ritorno);
  156.         }
  157.     }
  158.    
  159.     /* Codice del padre */
  160.     /* Il padre chiude i lati delle pipe che non usa */
  161.     for (i=0; i < N; i++)
  162.         close(piped[i][1]);
  163.  
  164.     /* Il padre recupera le informazioni dai figli in ordine di indice */
  165.     for (i=0; i < N; i++)
  166.     {
  167.         /* il padre recupera tutti i valori interi dai figli */
  168.         read(piped[i][0], &valore, sizeof(valore));
  169.         /* stampa non richiesta, ma che male non fa */
  170.         printf("DEBUG-Il figlio di indice %d ha convertito il valore %d per il file %s\n", i, valore, argv[i+1]);
  171.         somma = somma + (long int)valore;
  172.     }  
  173.     printf("La somma risultante derivante dai valori comunicati dai figli e' %ld\n", somma);
  174.  
  175.     /* Il padre aspetta i figli */
  176.     for (i=0; i < N; i++)
  177.     {
  178.         if ((pid = wait(&status)) < 0)
  179.         {
  180.         printf("Errore in wait\n");
  181.         exit(5);
  182.         }
  183.  
  184.         if ((status & 0xFF) != 0)
  185.                 printf("Figlio con pid %d terminato in modo anomalo\n", pid);
  186.             else
  187.         {   ritorno=(int)((status >> 8) &   0xFF);
  188.             if (ritorno==255)
  189.                 printf("Il figlio con pid=%d ha ritornato %d e quindi vuole dire che il figlio ha avuto dei problemi oppure il nipote non è riuscito ad eseguire il wc oppure è terminato in modo anormale\n", pid, ritorno);
  190.             else    printf("Il figlio con pid=%d ha ritornato %d\n", pid, ritorno);
  191.         }
  192.     }
  193.     exit(0);
  194. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement