1

I have create following test case for simulating the issue.I have compiled the source code and able to simulate the issue.

1)When the system command,we got some console out ( i.e your job submitted) which is redirect to file using dup2 and create file .stdout.

When I try to read this file as I need job submission information and I did not get data which was on console out. I was able to get data which I wrote it.( confirm file operation).

Can we not read console output from the file which is create by the child process.

*change rundir and cmd

#include <string>
#include <vector>
#include <utility>
#include <sstream>
#include <fstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <functional>
#include <map>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
int child();
int main()
{
    string rundir = "/temp";
    pid_t id =child();
    string _xafile;
    string _afile;
    string _afilecmd;
    string line;
    stringstream ss(stringstream::in | stringstream::out);
    ss<<int(id);
    _xafile = rundir;
    _xafile = _xafile + "/" + ss.str()+".stdout";
    cout<<" _xafile is "<<_xafile<<endl;
    string cmd ="cat "+ _xafile + ">" + rundir + "/" + "process.txt";
    _afile = rundir;
    _afile = _afile + "/" + "process.txt";
    _afilecmd = "rm -rf "+ _afile;
    system(cmd.c_str());
    ifstream xafile(_afile.c_str());
     while(xafile)
        {
            string word;
            xafile >> word;
            cout<<word<<"    ";
            /* try to read console output but did not read data */
        }
    system(_afilecmd.c_str());
    return 0;
}


int child()
{
    string rundir = "/tmp";
    string cmd    = " tool <input file> -o <outputfile>";
    const char* std_out_file;
    pid_t pid = fork();
    if (pid < 0) {
    return -1;
    }
    if (pid == 0) {
    pid_t mypid = getpid();
    stringstream sm;
    sm << rundir << "/";
    if (strlen(std_out_file) == 0)
        sm << mypid << ".stdout";
    else
        sm << std_out_file;

    int fd = open(sm.str().c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
    dup2(fd, 1);
    dup2(fd, 2);
    int fd2 = open("/dev/zero", O_RDONLY);
    dup2(fd2, 0);
     cout<<cmd <<endl<<endl;    
  //    execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
    system(cmd.c_str());

    /*When system call it generate console output like : your job submitted */
    /* redirect to file */   
    exit(-1);
  } 

    if (pid > 0)
    return pid;

    cout<<" child is done"<<endl;
    return 0;
}
Deanie
  • 2,316
  • 2
  • 19
  • 35
user765443
  • 1,856
  • 7
  • 31
  • 56
  • 2
    Consider fixing indentation of code in your question. Btw, you would have avoided that mess, if you used "use spaces instead of tabs" option of your editor... – hyde Mar 09 '13 at 12:14
  • 1
    It seems you should use `dup2` _before_ writing to stdout. – Nikolay Polivanov Mar 09 '13 at 12:35
  • I did not get you.it already generating file processid.stdout which I need to read – user765443 Mar 09 '13 at 12:42
  • 1
    You normally give a program `/dev/null` as standard input, not `/dev/zero`. Any process that reads standard input will never stop if you give it `/dev/zero` since it has an infinite supply of zero bytes for processes to read. You should always check that an `open`-like operation succeeds; ploughing ahead blindly after a failure can lead to problems. After using `dup()` or `dup2()` to replicate a file descriptor to standard input, standard output or standard error, you should almost invariably close the original file descriptor. – Jonathan Leffler Mar 09 '13 at 15:54
  • Using `chdir()` just before the `execl()` is unusual; is that working as you intend? (Have you printed out the value of `wd`? Which directory was the process in before you did the `chdir()`?) Have you considered reporting the error if the `execl()` fails? It might help you determine what's going wrong. (But it is good that you are exiting after the return from `execl()`, because a return always means it failed.) Have you printed out the value of `cmd`? – Jonathan Leffler Mar 09 '13 at 16:01
  • I could not understand why are we require two dup2 with 1 and fd2 dup statement – user765443 Mar 09 '13 at 16:01
  • Ya it is working code last 2 year.I got enhancement on this project – user765443 Mar 09 '13 at 16:02
  • The `dup2(fd, 1)` call ensures that standard output is written to the file; the `dup2(fd, 2)` call ensures that standard error is also written to the same file; the `dup2(fd2, 0)` call ensures that standard input is coming from `/dev/zero` — assuming that all the calls succeed. – Jonathan Leffler Mar 09 '13 at 16:05
  • I think you should show us an SSCCE ([Short, Self-Contained, Correct Example](http://sscce.org/)) and the input for the command to be executed. Either you should drop the `chdir()` or you must show the code the determines `wd`. But it should be as short as possible; no extraneous variables or functions. – Jonathan Leffler Mar 09 '13 at 16:07
  • Thanks for quick response.Could you give me some how can I read those file.I have tried with my sample code (above) but did not work for me. – user765443 Mar 09 '13 at 16:08
  • Succinctly, no — I can't show you how to read the files because I can't see how you're creating them because you've not given an SSCCE. I don't know what your `chdir()` is doing. I don't know how your parent process is processing stuff. I don't know know what your 'How can I maintain a variable between two processes' question is about, but it is likely relevant. There just isn't enough information to go on. And the fact that you don't always check that operations worked makes the code very fragile, too. – Jonathan Leffler Mar 09 '13 at 16:16
  • If the command you're executing is `/usr/bin/sometool filename -o anothername`, there won't be anything in the standard output file to read if the command succeeds — assuming that the `-o` option means 'write output to named file', which is normal for `-o`. You'd only get anything in the file you created if the executed command writes to its standard output or standard error. – Jonathan Leffler Mar 09 '13 at 16:20
  • am I able to provide complete information? – user765443 Mar 09 '13 at 16:30
  • It's not an SSCCE; I can't copy the code and compile it and run it. I have to add headers and a `main()`. See the [SSCCE](http://stackoverflow.com/questions/15312482/how-to-center-text-in-c-console/15313459#15313459) examples here. Granted, that's a simpler problem, but you can copy the code and paste it into a file, compile it and run it. That's an SSCCE! – Jonathan Leffler Mar 09 '13 at 17:05
  • I have compile code only change in rundir and cmd. – user765443 Mar 10 '13 at 04:41

1 Answers1

1

It's not entirely clear what your thinking is here - your code appears to fork a child which does a bunch of fancy io stuff to try and redirect your applications stdout to a file, and then runs a command with system(). The command in your code has it's own redirects, specifically via "-o" so it probably isn't writing to stdout.

Back in the parent process, you try to open for reading the same file your child process will open for writing. You've got no synchronization, so they could happen in any order. You appear to be trying to use "cat" to read the file and trying to read the stdout of the cat?

What I think you are actually trying to do is the C/C++ equivalent of Perl's

$foo = `ls -l /tmp`;

or something similar - to execute a command and capture the output.

A better way to do this would be to use pipes.

#include <iostream>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

enum { WritePipe = 1, ReadPipe = 0 };

int main(int argc, const char** argv)
{
    int pipes[2];   // each process is going to have its own file descriptor.
    if(pipe(pipes) != 0) {
        perror("pipe failed");
        return -1;
    }

    pid_t pid = fork();
    if(pid == 0) {
        // child
        close(pipes[ReadPipe]); // close the parent pipe in our context.

        // redirect stdout and stderr to the pipe.
        dup2(pipes[WritePipe], STDOUT_FILENO);
                    dup2(pipes[WritePipe], STDERR_FILENO);
                    // close(STDERR_FILENO); // <- or just do this to close stderr.

        int result = system("ls -ltr /etc");
        close(pipes[WritePipe]);
        return result;
    }

    if(pid < 0) {
        perror("fork failed");
        return -1;
    }

    // Parent process has launched the child.
    close(pipes[WritePipe]);

    char buffer[4097];
    int bytesRead;
    while((bytesRead = read(pipes[ReadPipe], buffer, sizeof(buffer) - 1)) > 0) {
        buffer[bytesRead] = 0;
        std::cout << buffer;
    }
    std::cout << std::endl;

    close(pipes[ReadPipe]);

    return 0;
}
kfsone
  • 23,617
  • 2
  • 42
  • 74