monolith937
monolith937

Reputation: 459

System function doesn't output anything

I've been tinkering around pipes and parent-child communication, only now I used a system function call to pass something from the child to the parent. Problem is I believe system doesn't really have any output in my example.

The parent reads input and sends it to the child to check if the string is of "sorted letters". Characters would have to be in lexicographic order. I used system to combine echo and grep and send that result back into the pipe. I was able to narrow it down to the parent's read-end of the the pipe; it blocks. I'm guessing that's because there is nothing in the pipe to be read and the write end isn't closed. I understand that would be the cause of the problem, for that to make sense, system would not have to output anything.

  /*
$ ./grep
AeIoU
Yes.
blah
No.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <ctype.h>


#define     STRING_SIZE 128

static void     fatalError(char* message);          
int     checkIfAlpha(char   *string, int length);   //f-ja koja proverava da li se string sastroji samo od slova

int main(int argc, char const *argv[])
{

    pid_t   pid;
    char    input[STRING_SIZE];     //cuvamo input string ovde
    char    command[100 + STRING_SIZE];
    int     pipeToParent[2], pipeToChild[2];
    int     n;
    char    tmp[50];
    int     count;


    if (pipe(pipeToParent) < 0)
        fatalError("pipe error");

    if (pipe(pipeToChild) < 0)
        fatalError("pipe error");

    if ((pid = fork()) < 0)
        fatalError("fork error");
    else if (pid == 0) {
            //child
        if (close(pipeToChild[1]) < 0)
            fatalError("close error");

        if (close(pipeToParent[0]) < 0)
            fatalError("close error");

        if (dup2(pipeToParent[1], STDOUT_FILENO) < 0)
            fatalError("dup2 error");

        while (1) {

        if ((count = read(pipeToChild[0], tmp, 50)) < 0)
            fatalError("read error");
        fprintf(stderr, "2\n");
        if (count == 0)
            break;
        sprintf(command, "echo '%s' | grep -i ^a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*w*x*y*z*$", tmp);

        if (system(command) < 0) 
            fatalError("system error");

        fprintf(stderr, "3\n"); 

        }

        exit(EXIT_SUCCESS);


    }

    //parent

    if (close(pipeToParent[1]) < 0)
        fatalError("close rror");


    if (close(pipeToChild[0]) < 0)
        fatalError("close error");

    while(fgets(input, STRING_SIZE, stdin) != NULL) {

        input[strlen(input)-1] = '\0';


            if (checkIfAlpha(input, strlen(input)) == -1) {
                fprintf(stderr, "Samo slova\n");
                continue;
            }
            if (write(pipeToChild[1], input, strlen(input)) != strlen(input))
                fatalError("write error");
            printf("1\n");

            if ((n = read(pipeToParent[0], input, STRING_SIZE)) < 0)
                fatalError("fatal error");
            printf("4\n");

            if (n == 0)
                printf("No\n");
            else if (n > 0)
                printf("Yes\n");

    }

    exit(EXIT_SUCCESS);

}


static void     fatalError(char *message) {
    perror(message);
    exit(EXIT_FAILURE);
}

int     checkIfAlpha(char   *string , int   length) {

    int c = 1;

    for (int i = 0; i < length; i++)
        if (!isalpha(string[i])) {
            c = -1;
            break;
        }

    return c;
}

EDIT: I would've posted the outputs if I thought they would be that significant, but by all means.

Here's the output (with the right input):

./grep 
abcde
1
2
3

Here's GDB:

Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe058) at grep.c:23
23  {
(gdb) next
34      if (pipe(pipeToParent) < 0)
(gdb) 
37      if (pipe(pipeToChild) < 0)
(gdb) 
40      if ((pid = fork()) < 0)
(gdb) 
42      else if (pid == 0) {
(gdb) 
76      if (close(pipeToParent[1]) < 0)
(gdb) 
80      if (close(pipeToChild[0]) < 0)
(gdb) 
83      while(fgets(input, STRING_SIZE, stdin) != NULL) {
(gdb) 

85          input[strlen(input)-1] = '\0';
(gdb) 
88              if (checkIfAlpha(input, strlen(input)) == -1) {
(gdb) 
92              if (write(pipeToChild[1], input, strlen(input)) != strlen(input))
(gdb) 
94              printf("1\n");
(gdb) 
1
96              if ((n = read(pipeToParent[0], input, STRING_SIZE)) < 0)
(gdb) 

Upvotes: 1

Views: 119

Answers (1)

Eric Postpischil
Eric Postpischil

Reputation: 222467

read does not write a terminating null character. After if ((count = read(pipeToChild[0], tmp, 50)) < 0), the program passes tmp, without writing a null charactering into it, to sprintf.

This results in the echo command being passed additional garbage data from tmp beyond what was read from the pipe, which in turn causes grep not to find a matching string.

One fix would be to change the read to read(pipeToChild[0], tmp, sizeof tmp - 1) and insert tmp[count] = 0;.

Upvotes: 1

Related Questions