0

I have to create a program where i have P0 as parent process and P1,...,PN children processes. Every child has to perform grep in a file and return the output in a pipe. Then P0 has to read the message and count the lines and print into stdout a sentence containing that number. The problem is that every child is terminated involuntarily with the signal 13. Why does it happen? Here's my code:

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>

//eventuali define
#define MAXDIM 255
#define MAXPID 30

//global var declaration
int fd;
int pipefd[MAXPID][2];

//func declaration
void print_usage(char* prog_name);
void wait_child();
void codice_figlio(int index, char *word, char *filename);
void handler(int signo);
int conta_righe(char *str);

int main(int argc, char *argv[]) {
//    local var declaration
    int N = argc - 2;
    int pid[MAXPID];
    int i, num;
    char buf[MAXDIM];

    if (argc < 3) {
        fprintf(stderr, "Numero di parametri non valido\n");
        print_usage(argv[0]);
        exit(EXIT_FAILURE);
    }
    for (i = 1; i <= N; i++) {
        if ((fd = open(argv[i], O_RDONLY)) < 0) {
            perror("Errore nell'apertura del file");
            exit(EXIT_FAILURE);
        }
        close(fd);
    }
    signal(SIGUSR1, handler);
    for (i = 0; i < N; i++) {
        pid[i] = fork();
        if (pipe(pipefd[i]) < 0) exit(-3);
        if (!pid[i]) {
            pause();
            codice_figlio(i, argv[argc - 1], argv[i + 1]);
        }
        else if (pid[i] < 0) {
            perror("fork error");
            exit(-3);
        }
        sleep(1);
        kill(pid[i], SIGUSR1);
        close(pipefd[i][1]);
        read(pipefd[i][0], buf, sizeof(int));
        num = conta_righe(buf);
        printf("Nel file %s sono state trovate %d occorrenze di %s.\n", argv[i + 1], num, argv[argc - 1]);
    }
    for (i = 0; i < N; i++) {
        wait_child();
        close(pipefd[i][0]);
        close(pipefd[i][1]);
    }
    return 0;
}

void print_usage(char* prog_name){
    fprintf(stderr, "Usage:\n\t%s file1 file2 ... fileN parola\n", prog_name);
}

void wait_child() {
    int status, pid;
    pid = wait(&status);
    printf("*P0 (pid = %d): Terminato processo figlio PID = %d: ", getpid(), pid);
    if ((char)status == 0) printf("Terminazione volontaria con stato %d\n", status>>8);
    else printf("Terminazione involontaria per segnale %d\n", (char)status);
}

void codice_figlio(int index, char *word, char *filename) {
    close(pipefd[index][0]);
    close(1);
    dup(pipefd[index][1]);
    close(pipefd[index][1]);
    execlp("/bin/grep", "grep", word, filename, (char*)0);
    perror("Problemi con la grep");
    exit(EXIT_FAILURE);
}

void handler(int signo) {
    return;
}

int conta_righe(char *str) {
    int res = 0, i = 0;
    while (str[i] != '\0') {
        if (str[i] == '\n') res++;
        i++;
    }
    return res;
}
1
  • Didn't study you code in detail, but if you close the read end of the pipe on the parent the child has nothing to write to and gets the SIGPIPE. This is where commenting your code helps you: for each of these close() calls, what is actually closed?
    – xenoid
    Commented Apr 20, 2020 at 17:25

1 Answer 1

1

Move the if (pipe(pipefd[i]) < 0) before the fork(). Otherwise you're just creating two separate pipes (in the parent and in the child), and you'll get a SIGPIPE when you close the writing end of the pipe in the child (in the codice_figlio() function), since it's the only reference to it, not a descriptor shared between the parent and the child.

That's not the only problem; read(pipefd[i][0], buf, sizeof(int)); is broken, because you'll only read 4 bytes from the pipe, but your conta_righe() function tries to count the number of lines in it. Change the sizeof(int) to sizeof buf.

After this, your code seems to do something sensible:

$ ./fo fo.c fo.c pipefd
Nel file fo.c sono state trovate 8 occorrenze di pipefd.
Nel file fo.c sono state trovate 8 occorrenze di pipefd.
*P0 (pid = 9541): Terminato processo figlio PID = 9542: Terminazione volontaria con stato 0
*P0 (pid = 9541): Terminato processo figlio PID = 9543: Terminazione volontaria con stato 0

This is a patch to your code (apply by hand, this site mangles tabs):

--- fo.c~   2020-04-20 20:51:19.540914204 +0300
+++ fo.c    2020-04-20 20:51:22.648914269 +0300
@@ -42,8 +42,8 @@
     }
     signal(SIGUSR1, handler);
     for (i = 0; i < N; i++) {
-        pid[i] = fork();
         if (pipe(pipefd[i]) < 0) exit(-3);
+        pid[i] = fork();
         if (!pid[i]) {
             pause();
             codice_figlio(i, argv[argc - 1], argv[i + 1]);
@@ -55,7 +55,7 @@
         sleep(1);
         kill(pid[i], SIGUSR1);
         close(pipefd[i][1]);
-        read(pipefd[i][0], buf, sizeof(int));
+        read(pipefd[i][0], buf, sizeof(buf));
         num = conta_righe(buf);
         printf("Nel file %s sono state trovate %d occorrenze di %s.\n", argv[i + 1], num, argv[argc - 1]);
     }

1
  • Thank you so much! It works perfectly now! Commented Apr 20, 2020 at 17:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .