5

I'm trying to create a child process, send the child process a command "LISTALL". The child process should then issue the system the command ps and return that list to the parent process. The parent process should then choose a process and kill it. This is what I have so far but I'm having trouble just getting it to run.

#include <stdio.h>
#include <unistd.h>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <sys/wait.h>

char* getlistOfProcesses(const char* cmd) 
{
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return (char*)"ERROR";
    char buffer[128];
    char *result = new char[1024];
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
            strcat(result, buffer);
    }
    pclose(pipe);
    return result;
}

int spawnGEdit()
{
    pid_t gPid = fork();
    if(gPid == 0)
    {
        execl("gedit", "gedit", NULL);
        exit(-1);
    }
    else
    {
    }
    return 0;
}

int main(int argc, char **argv)
{   
    int P2C[2];
    int C2P[2];
    pipe(P2C);
    pipe(C2P);
    pid_t cPid = fork();
    char cmd[50];
    char* listOfProcesses = new char[1024];
    spawnGEdit();

    if (cPid == 0)
    {
        close(P2C[1]); 
        close(C2P[0]); 
        read(P2C[0], cmd, 10);
        if(strcmp(cmd,"LISTALL") == 0)
        {
            write(C2P[1], getlistOfProcesses("ps"), 1024);
            close(P2C[0]);
            close(C2P[1]);
        }
    }
    else if (cPid > 0)
    {
        close(C2P[1]); 
        close(P2C[0]); 
        write(P2C[1], "LISTALL", 10);
        wait(NULL);
        read(C2P[0], listOfProcesses,1024);
        printf("%s",listOfProcesses); 
        //TODO
        //get user input of a PID
        //kill the PID
        close(C2P[0]);
        close(P2C[1]);
    }
    else
    {
        // fork failed
        printf("Forking failed!\n");
        exit(1);
    }
    return 0;
}

These are the errors I'm getting when I try to compile it:

/tmp/cciTPIOZ.o: In function `getlistOfProcesses(char const*)':
test.cpp:(.text+0x53): undefined reference to `operator new[](unsigned long)'
/tmp/cciTPIOZ.o: In function `main':
test.cpp:(.text+0x166): undefined reference to `operator new[](unsigned long)'
/tmp/cciTPIOZ.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cpp:(.text+0x2c0): undefined reference to `std::ios_base::Init::Init()'
test.cpp:(.text+0x2cf): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status

I'm compiling with with:

cc test.cpp -o test
  • I am a fan of popen(). So what problem are you having? Does it compile? Does it hang? any output show? You tried X, expected Y, and observed Z. Describe X, Y, and Z – 2785528 Jun 14 '15 at 03:34
  • can you explain a bit more on what you mean by getting it to run ? – Pradheep Jun 14 '15 at 03:34
  • 2
    [If you look up the documentation for `popen`](http://pubs.opengroup.org/onlinepubs/009695399/functions/popen.html), you'll notice it's declared as: `FILE *popen(const char *command, const char *mode)`. `command` is a `const char *`, but you've got a `std::string`. Those are not the same data types. Calling [`.c_str()`](http://en.cppreference.com/w/cpp/string/basic_string/c_str) on your `cmd` might be what you need (though I think you've got more errors than just that one). – Cornstalks Jun 14 '15 at 03:44
  • 1
    You say you're trying to do A, B, C, D, E and F, and that what you have written so far doesn't compile. **Try something simpler,** then build up. – Beta Jun 14 '15 at 03:45
  • In main() you do 2 forks, was that intentional? – Kam Jun 14 '15 at 03:57
  • Kam, do you mean 2 pipes? If so yes because I need each process to both read and write. – ILikeToLearn Jun 14 '15 at 03:58
  • @ILikeToLearn 2 forks, the spawnGEdit and main both have fork commands – Kam Jun 14 '15 at 05:32
  • @Kam Yes, that was intentional. The GEdit fork is just to spawn the GEdit process. the other one is in order to spawn a child process. The parent process will then send the listall "command" and the child will respond with the list of all processes. I then have to kill one through the parent, I want to kill something I know so I spawned that other gEdit. Thanks for watching out though! – ILikeToLearn Jun 14 '15 at 06:22
  • How is all the multiprocessing related to the linker errors? You should reduce your problems as much as possible before posting here, which includes removal of irrelevant parts. – Ulrich Eckhardt Jun 14 '15 at 06:36

1 Answers1

2

Compilation Errors occurred on line number:9,53,64 can be solved by using these:

line 9: FILE* pipe = popen(cmd.data(), "r");

line 53: write(C2P[1], getlistOfProcesses("ps").data(), 1024);

line 64: printf("%s",listOfProcesses.data());

Reason: These popen,write,printf requires char* as their arguments but you are passing them std::string. You have to use std::string.data() function instead as it returns pointer to the character array represented by std::string object.

And for your error on line 63, refer this.

PS:- For your edits in question:

line 10: if (!pipe) return (char*)"ERROR";

line 12: char *result = new char[1024];

line 53: (change in line 7) char* getlistOfProcesses(const char* cmd)

A bit of advice: use wait(NULL); in parent process before reading listOfProcesses and exit(0); at the end of child process.

Working code:

#include <stdio.h>
#include <unistd.h>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <sys/wait.h>

char* getlistOfProcesses(const char* cmd) 
{
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return (char*)"ERROR";
    char buffer[128];
    char *result = new char[1024];
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
            strcat(result, buffer);
    }
    pclose(pipe);
    return result;
}

int spawnGEdit()
{
    pid_t gPid = fork();
    if(gPid == 0)
    {
        execl("gedit", "gedit", NULL);
        exit(-1);
    }
    else
    {
    }
    return 0;
}

int main(int argc, char **argv)
{   
    int P2C[2];
    int C2P[2];
    pipe(P2C);
    pipe(C2P);
    pid_t cPid = fork();
    char cmd[50];
    char* listOfProcesses = new char[1024];
    spawnGEdit();

    if (cPid == 0)
    {
        close(P2C[1]); 
        close(C2P[0]); 
        read(P2C[0], cmd, 10);
        if(strcmp(cmd,"LISTALL") == 0)
        {
            write(C2P[1], getlistOfProcesses("ps"), 1024);
            close(P2C[0]);
            close(C2P[1]);
        }
        exit(0);
    }
    else if (cPid > 0)
    {
        close(C2P[1]); 
        close(P2C[0]); 
        write(P2C[1], "LISTALL", 10);
        wait(NULL);
        read(C2P[0], listOfProcesses,1024);
        printf("%s",listOfProcesses); 
        //TODO
        //get user input of a PID
        //kill the PID
        close(C2P[0]);
        close(P2C[1]);
    }
    else
    {
        // fork failed
        printf("Forking failed!\n");
        exit(1);
    }
    return 0;
}
Milan Patel
  • 422
  • 4
  • 12
  • Thanks for this, I realized how stupid I was being at first, I did swap them to character arrays right now because I thought it would be easier, is there really any preference over which to use? – ILikeToLearn Jun 14 '15 at 04:20
  • 1
    No, but when you are using some standard functions, then you have to choose according to the arguments required by them. – Milan Patel Jun 14 '15 at 04:27
  • Well, changing things back to char* did the trick for the errors I think but it still doesn't compile, and thank you very much, that's good to know – ILikeToLearn Jun 14 '15 at 04:38
  • Thank you, I see why I'm getting a lot of the errors still, It's hard to get used to everything needing to be cast and declared differently. Also thanks for the advice. I made the changes and even tries copy pasting what you wrote but it still doesn't seem to want to compile. I've updated the original post. – ILikeToLearn Jun 14 '15 at 06:20