c++pipeforksystem-callsdup

send several strings through a pipe to a child process


I want the child process to listen in a loop the parent process. If it receives "exit" from the parent it terminates and if it receives "cmd" will read again for the actual command to execute using system(). So far I have this code, but the second reading just gives me the same ("cmd")

child:

pid = fork();
            if(pid == 0){           
            close(fd_pipe[1]);  // Close writing end
            dup2(fd_pipe[0],0); close(fd_pipe[0]);
            //close(fd_pipe[0]);

            //create file descriptor for user file
            int userFile_fd = 
            open(users_table.at(get_user(u_id)).get_filename().c_str(), O_APPEND|O_WRONLY);
            //redirect output to user file
            dup2(userFile_fd,1);
            close(userFile_fd);

            //listen in a loop till receive "exit"
            while(true){

                char buf[100];

                read (0, &buf, 100);
                cout << buf << endl;

                //logout
                if(strstr(buf, bye) != NULL){
                    cout << "Exiting..." << endl;
                    kill(getpid(), SIGKILL);
                    break;
                }

                //command
                else if(strcmp(buf, cmd) == 0){

                    read (0, &buf, 100);
                    cout << "reading buf again: "<<buf << endl;

                    system(buf);
                }
            }//end while

            }//end if (child process)

parent:


while(status == true){

    //get input
        cout << ("ucmd>");
        getline (cin, command);

//some preprocessing code and then...

        //this works fine
        else if(command.compare(logout)==0)
        {
            cout << " UM: Loggin out USER-"<<u_id<<" associated pipe ID: "<<user_pipe[u_id]<<endl;
            char exit2[] = "exit";
            write (user_pipe[u_id], exit2, sizeof(exit2));//sends exit message
        }

        //cmd
        else if(command.compare(cmd)==0)
        {   

            write (user_pipe[u_id], cmd, sizeof(cmd));//cmd command
            write (user_pipe[u_id], argument.c_str(), sizeof(argument.c_str()));//cmd command
            //call_cmd(u_id, argument);
        }

Solution

  • This looks wrong to me:

    write (user_pipe[u_id], cmd, sizeof(cmd));//cmd command
    write (user_pipe[u_id], argument.c_str(), sizeof(argument.c_str()));
    

    How is cmd defined? Your code is only correct if it is defined as a fixed size array of characters. The second line looks definitely wrong: argument.c_str() returns a char const *, so sizeof(argument.c_str()) will return sizeof(char const *) independent of the actual value of argument. You can try something like this:

    char const *carg = argument.c_str();
    write(user_pipe[u_id], carg, strlen(carg) + 1);
    

    That way the full string (including terminating NUL) should be transferred to the child.

    Then in the child I think you have to be more careful as well. You do

    read (0, &buf, 100);
    

    But then consume only the first NUL terminated string from buf. The read operation may have read more than that. You should check the return value. In particular, make sure that read returns a value > 0. Otherwise nothing may have been read (there may have been an error) and the contents of buf are unchanged.