A child process runs a bin file, which is provided by Qualcomm. The child process is invoked by my parent process, which is developed by me. When the child process is running, it always prints lots pieces of logs in shell command. So, am I able to redirect Qualcomm's outstream from stdout to another file in the parent process? As you know, it's nearly impossible to push Qualcomm to update this bin file. Thanks a lot~
-
Is that really an appropriate duplicate? I think this question is about sending the child's output to an actual file, not processing it in the parent's memory. – aschepler Aug 30 '18 at 03:19
-
What about this https://stackoverflow.com/a/40667558/2193968 (replacing /dev/null with some other file) – Jerry Jeremiah Aug 30 '18 at 03:56
-
@JerryJeremiah Thanks. But in the demo code , the redirecting is involved in child process... – Perlman Song Aug 30 '18 at 04:34
-
@aschepler yes, to redirect child process's outstream to an actual file . But the bin file running in child process can not be modified, so is it possible for parent process to control the redirection of child process? – Perlman Song Aug 30 '18 at 04:40
-
Would something like system(“./qualcommbinary > out.txt”) suffice? – Jeremy Friesner Aug 30 '18 at 05:00
-
this is worth reading: http://www.rozmichelle.com/pipes-forks-dups/ – Richard Hodges Aug 30 '18 at 06:41
3 Answers
The key piece here is the POSIX function dup2, which lets you essentially replace one file descriptor with another. And if you use fork (not system), you actually have control of what happens in the child process between the fork and the exec* that loads the other executable.
#include <cstdlib>
extern "C" {
#include <fcntl.h>
#include <unistd.h>
}
#include <stdexcept>
#include <iostream>
pid_t start_child(const char* program, const char* output_filename)
{
pid_t pid = fork();
if (pid < 0) {
// fork failed!
std::perror("fork");
throw std::runtime_error("fork failed");
} else if (pid == 0) {
// This code runs in the child process.
int output_fd = open(output_filename, O_WRONLY | O_CREAT | O_TRUNC);
if (output_fd < 0) {
std::cerr << "Failed to open log file " << output_filename << ":"
<< std::endl;
std::perror("open");
std::exit(1);
}
// Replace the child's stdout and stderr handles with the log file handle:
if (dup2(output_fd, STDOUT_FILENO) < 0) {
std::perror("dup2 (stdout)");
std::exit(1);
}
if (dup2(output_fd, STDERR_FILENO) < 0) {
std::perror("dup2 (stderr)");
std::exit(1);
}
if (execl(program, program, (char*)nullptr) < 0) {
// These messages will actually go into the file.
std::cerr << "Failed to exec program " << program << ":"
<< std::endl;
std::perror("execl");
std::exit(1);
}
}
return pid;
}
- 68,873
- 9
- 101
- 151
-
Small fix: O_CREATE should be O_CREAT I believe you also need to use STDOUT_FILENO, STDERR_FILENO and not stdout, stderr directly. – Xavier Leclercq May 23 '20 at 12:49
-
It is possible, for POSIX, because the POSIX shells do this. Executing a program has two steps, for POSIX. First use fork to clone the parent process to create the child process. Then have the child process use one of the exec family of system calls to execute the chosen program instead of the program of the parent. In between those two steps the code executing for the child process can do additional operations, which will affect the environment of the program to be executed. In particular, the code could open a file descriptor to the file to be redirected to, close the stdout file descriptor, then duplicate the file's file descriptor to the value (1) used for stdout.
- 43,666
- 36
- 142
- 227
You could create own pipes and attach them to the child process.
- Create 3 pipes. they are going to replace stdin, stdout, stderr of the child.
fork()- In subprocess
close()the parent end of the pipes. Close stdin,stdout and stderr. - The parent process
close()the child end of the pipes. dup2()the pipe ends in the child process that are intended to work as the new stdin,out,errexec()the child.
Now you got all Output from the child to the pipe in the parent. Ofcourse you need to read from the pipes that come from the child or it will block on any write to the stdout/stderr. For this you could use a select(), poll(), epoll() multiplexing algorithm.
See
https://linux.die.net/man/2/pipe
https://linux.die.net/man/2/dup2
- 712
- 5
- 18