I want to analyse the output of strace in my C++ program. While launching /bin/strace ps from my app I get an output from ps, but not from strace and strace output is printed to stdout (my terminal). I use standard technique of using pipes and redirecting streams.
Here is my source:
#include <stdlib.h>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
int main(){
char *const parmList[] = {"/bin/strace", "ps", NULL};
int pipes[2];
pipe(pipes);
pid_t child = fork();
if(child == 0){
close(pipes[0]);
dup2(pipes[1],1);
execv(parmList[0], parmList);
}
else{
int status;
wait(&status);
fcntl(pipes[0], F_SETFL, O_NONBLOCK | O_ASYNC);
char buf[128] = {0};
ssize_t bytesRead;
std::string stdOutBuf;
while(1) {
bytesRead = read(pipes[0], buf, sizeof(buf)-1);
if (bytesRead <= 0)
break;
buf[bytesRead] = 0;
stdOutBuf += buf;
}
std::cout << "<stdout>\n" << stdOutBuf << "\n</stdout>" << std::endl;
}
close(pipes[0]);
close(pipes[1]);
return 0;
}
How can I get an output of strace in my program?
strace writes to stderr not to stdout, if you only want to capture the strace output just use stderr instead of stdout
change the dup2 line like this
dup2(pipes[1],2);
If you want combined strace and ps output do this:
dup2(pipes[1],1);
dup2(pipes[1],2);
if you want separated output you'll probably need to use non-blocking reads and select() or poll()
Also: after calling exec you should print an error message, if everything works exec won't return, but if something goes wrong with the exec, it's good to know.
std::cerr << "exec failed!";
I used this code and had success:
#include <stdlib.h>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
int main(){
char *const parmList[] = {"/usr/bin/strace", "ps", NULL};
int pipes[2];
pipe(pipes);
pid_t child = fork();
if(child == 0){
close(pipes[0]);
dup2(pipes[1],2);
execv(parmList[0], parmList);
std::cerr << "exec fail\n" ;
}
else{
int status;
wait(&status);
fcntl(pipes[0], F_SETFL, O_NONBLOCK | O_ASYNC);
char buf[128] = {0};
ssize_t bytesRead;
std::string stdOutBuf;
while(1) {
bytesRead = read(pipes[0], buf, sizeof(buf)-1);
if (bytesRead <= 0)
break;
buf[bytesRead] = 0;
stdOutBuf += buf;
}
std::cout << "<stdout>\n" << stdOutBuf << "\n</stdout>" << std::endl;
}
close(pipes[0]);
close(pipes[1]);
return 0;
}
HTH
Related
I am creating 10 children to one parent. I want all the children to write into a pipe appending the pipe, so I can then read the collective data later in the parent.
So first child writes into the pipe "9-6" then the second child writes "9-6" making the contents inside the pipe "9-6 9-6"
but what I have discovered here is that Every child when open the pipes for writing inside it. It truncates the pipe.
Is there a way I can just keep on adding content into the pipe and eventually in the end just read it.
#include <fcntl.h> //
#include <stdio.h> //
#include <stdlib.h> //
#include <string.h> //
#include <sys/types.h> //
#include <sys/wait.h> //
#include <sys/stat.h> //
#include <termios.h> //
#include <unistd.h>
#include <iostream>
using namespace std;
int main()
{
pid_t pids[10]; //10 children
int i;
int n = 10;
int f1 = mkfifo("p", 0666); //making named pipe
if (f1 < 0)
std::cerr << "Pipe not created";
char str[256] = "9-6"; //character array that every child writes in the pipe
char read_char[256] = "";
/* Start children. */
for (i = 0; i < 10; ++i) {
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {\
int fifo_write = open("p", O_WRONLY); //open the pipe for writing
if (fifo_write < 0)
{
std::cerr << "Pipe could not be created";
return 0;
}
else
{
write(fifo_write, str, sizeof(str)); //write char str[] and close the pipe
close(fifo_write);
exit(0);
}
}
}
/* Wait for children to exit. */
int count(0);
int fifo_read = open("p", O_RDONLY);
char str1[256] = "";
if (fifo_read < 0)
{
std::cerr << "Pipe could not be created";
}
else
{
read(fifo_read, str1, sizeof(str));
cout << str1 << endl;
count++;
close(fifo_read);
}
cout << "the count is " << count << endl;
unlink("p");
}
I have also tried first reading the pipe and appending what is read from the pipe with "9-6" and then writing in the pipe again.
The implementation of that looks like this
#include <fcntl.h> //
#include <stdio.h> //
#include <stdlib.h> //
#include <string.h> //
#include <sys/types.h> //
#include <sys/wait.h> //
#include <sys/stat.h> //
#include <termios.h> //
#include <unistd.h>
#include <iostream>
using namespace std;
int main()
{
pid_t pids[10];
int i;
int n = 10;
int f1 = mkfifo("p", 0666); //Making named pipe
if (f1 < 0)
std::cerr << "Pipe not created";
char str[256] = "9-6";
char read_char[256] = "";
/* Start children. */
for (i = 0; i < 10; ++i) {
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
//here I open the pipe for read so that I can read what inside and concatenate it with 9-6 //so every time it is concatenated with 9-6 and written back in the pipe
int fifo_read = open("p", O_RDONLY);
if (fifo_read < 0)
{
std::cerr << "Pipe could not be created";
return 0;
}
else
{
read(fifo_read, read_char, sizeof(read_char));
strcat(str, read_char);
close(fifo_read);
}
int fifo_write = open("p", O_WRONLY);
if (fifo_write < 0)
{
std::cerr << "Pipe could not be created";
return 0;
}
else
{
write(fifo_write, str, sizeof(str));
close(fifo_write);
exit(0);
}
}
}
/* Wait for children to exit. */
int count(0);
int fifo_read = open("p", O_RDONLY);
char str1[256] = "";
if (fifo_read < 0)
{
std::cerr << "Pipe could not be created";
}
else
{
read(fifo_read, str1, sizeof(str));
cout << str1 << endl;
count++;
close(fifo_read);
}
cout << "the count is " << count << endl;
unlink("p");
}
But when I do this mkfifo fails and "pipe not created" is printed
I have a scenario where a spawned child process is killed when the parent is killed with SIGABRT. In my understanding, the child should continue to run. To mimic the actual code, I created two files presenting child and parent. The parent writes to a pipe and child reads from the read end (STDIN_FILENO).
parent code -> parent.cpp
#include <iostream>
#include <stdlib.h>
#include <string>
#include <unistd.h>
int main() {
int pipefd[2];
std::string message = "test\n";
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
int pid = fork();
if (0 == pid) {
std::cout << "Inside child process\n";
close(pipefd[1]);
char *args[] = {"./CHILD", NULL};
char *envp[] = {NULL};
if (dup2(pipefd[0], STDIN_FILENO) == -1) {
std::cout << "dup2 failed\n";
}
close(pipefd[0]);
close(pipefd[1]);
execve(args[0], args, envp);
} else {
close(pipefd[0]);
while (1) {
sleep(1);
std::cout << "parent writing -> " << message;
write(pipefd[1], message.c_str(), message.length());
}
}
return 0;
}
child code -> child.cpp
#include <iostream>
#include <string>
#include <unistd.h>
int main() {
std::string str;
char buf;
std::cout << "[child] started\n";
while (read(STDIN_FILENO, &buf, sizeof(buf)) > 0) {
if (buf != '\n')
str += buf;
else {
write(STDOUT_FILENO, str.c_str(), str.length());
str.clear();
write(STDOUT_FILENO, "\n", 1);
}
}
std::cout << "[child] Exiting the application\n";
return 0;
}
if the parent is killed with SIGABRT, the child also receives the same. When the pipe code is removed, the signal is not propagated.
Can you please provide some insight into it?
First off, Hello and thanks for your help!
I'm trying to get an understanding of IPC with unnamed pipes. Specifically, I'm going to be communicating with Maxima to expand an input that was grabbed from stdin and sent to the input Maxima and then that output is sent to stdout. So simply read input from stdin send it to the child and then write the output to stdout. Currently, I've gotten it to output:
Input ">(x+2)^2"
(%o2) x^2+4x+4
which is correct, but there is a newline between the input and output which shouldn't be there and the (%o2) comes from the Maxima formatted output, so that also should not be there.
I guess my question now comes to two things:
1) How do I fix my output so that it is formatted without the trailing newline and the output indicator?
2) What about the following code can I fix? What can I make better? and Why? (My code is not yet near completion because I have another segment I wish to write)
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <errno.h>
#include <iostream> // cin, cout
#include <signal.h>
using namespace std;
int main(int argc, char* argv[]){
pid_t pid;
int status;
int count;
int fpipe[2];
string start = "display2d:false$expand("; string end = ");"; string inp, sent;
string quit = "quit();";
string buffer;
if(pipe(fpipe)){cerr<<"Pipe Failure" << endl; exit(1);}
if((pid = fork()) < 0){ cerr<<"Fork Failure"<<endl; exit(2);}
if(pid == 0){ // child process
close(0); // close stdin
dup(fpipe[0]); // copy stdin
close(fpipe[1]);
execlp("maxima", "maxima", "-q", (char*)0);
read(fpipe[0], (void*)buffer.c_str(), buffer.length());
cout << buffer << " 1" << endl;
exit(EXIT_FAILURE);
}
else{
if(argc == 1){ // parent process
//close(fpipe[0]);
close(1); // close stdout
//dup(fpipe[1]); // redirect stdout
while(1){
cout << ">";
cin >> buffer;
if(buffer == "quit"){
break;
}
buffer = start+buffer+end+'\n';
int dp = write(fpipe[1], buffer.c_str(), buffer.length());
//cout << buffer << endl;
waitpid(getpid(), &status, 0);
}
}
else if(argc > 1){ // just do it for # of argc
}
}
return 0;}
Sample input and output
$./expand
> (x+2)^2
x^2+4*x+4
Current output
(%o#) x^2+4*x+4
I am trying to create a child that calls some program or process. The parent write and read some data from child through a two pipes. My code compiles and runs, but there is no text on input. What am I doing wrong? Am I not closing the pipes correctly, writing the pipes or outputting the data correctly?
#include <iostream>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
int main(){
int pipedes1[2],pipedes2[2];
char buff[256];
string text = "Hello";
pid_t pid;
pipe(pipedes1);
pipe(pipedes2);
pid = fork();
if(pid > 0){
close(pipedes1[1]);
close(pipedes2[0]);
dup2(pipedes2[1], STDOUT_FILENO);
dup2(pipedes1[0], STDIN_FILENO);
execve("/home/pi/Test", NULL, NULL);
} else {
close(pipedes1[1]);
close(pipedes2[1]);
write(pipedes1[0], text.c_str(), text.length());
while((len = read(pipedes2[0], buff, 256)) != 0){
cout << buff << endl;
}
close(pipedes2[0]);
close(pipedes1[0]);
}
return 0;
}
And there is my "chield" program:
int main(){
string str;
cin >> str;
str = "echo " + str + " >> /home/pi/1";
cout << str << endl;
return 0;
}
Output of prog:
echo << /home/pi/1
Im found a problem write() returns -1.
But i dont know why?
write(pipedes1[0], text.c_str(), text.length());
You are writing to the reading end of the pipe.
Except for this, your application is endangered by deadlock. What if you are attempting to write so much that the pipe buffer fills up, and the child produces so much data that its pipe buffer fills up as well? Then both processes are waiting for the other to drain the buffer, but they are each blocked in write!
I have a simple example program that reads from std::cin and writes to std::cout. It works fine if run in cmd.exe or the visual studio debugger. The code (server.cpp):
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
int main(int argc, char* argv[])
{
std::string input;
while (std::getline(std::cin, input))
{
if (input == "dog")
{
std::cout << "cat" << std::endl;
}
else if (input == "white")
{
std::cout << "black" << std::endl;
}
else if (input == "quit")
{
std::cout << "exiting" << std::endl;
return 0;
}
else if (input != "")
{
std::cout << "unknown" << std::endl;
}
}
std::cout << "error" << std::endl;
}
Now I want to run this from another process that writes to its stdin and reads from its stdout. I create two pipes and start a process using CreateProcess with the read handle of one pipe as StdInput handle and the write handle of the other pipe as Stdouput handle. The Code (client.cpp):
#include <Windows.h>
#include <cassert>
#include <iostream>
#include <ostream>
#include <string>
namespace
{
class Server
{
public:
Server() :
m_pi()
{
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES)};
sa.bInheritHandle = TRUE;
assert(CreatePipe(&m_ro, &m_wo, &sa, 0));
assert(SetHandleInformation(m_ro, HANDLE_FLAG_INHERIT, 0));
assert(CreatePipe(&m_ri, &m_wi, &sa, 0));
assert(SetHandleInformation(m_ri, HANDLE_FLAG_INHERIT, 0));
STARTUPINFO si = {sizeof(STARTUPINFO)};
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = m_ri;
si.hStdOutput = m_wo;
assert(CreateProcess(L"..\\Debug\\server.exe", 0, 0, 0, 1, 0, 0, 0, &si, &m_pi));
}
~Server()
{
execute("quit\n");
assert(WaitForSingleObject(m_pi.hProcess, INFINITE) != WAIT_FAILED);
assert(CloseHandle(m_pi.hThread));
assert(CloseHandle(m_pi.hProcess));
assert(CloseHandle(m_wi));
assert(CloseHandle(m_ri));
assert(CloseHandle(m_wo));
assert(CloseHandle(m_ro));
}
std::string execute(std::string const& cmd)
{
DWORD num_bytes;
assert(WriteFile(m_wi, cmd.c_str(), (DWORD)cmd.size(), &num_bytes, 0));
std::string output;
DWORD n = 0;
while (n == 0)
{
Sleep(0);
assert(PeekNamedPipe(m_ro, 0, 0, 0, &n, 0));
if (n > 0)
{
output.resize(n);
assert(ReadFile(m_ro, &output[0], n, &num_bytes, 0));
}
}
return output;
}
private:
HANDLE m_wo, m_ro, m_wi, m_ri;
PROCESS_INFORMATION m_pi;
};
Server g_server;
}
int main(int argc, char* argv[])
{
std::cout << g_server.execute("white\n") << std::endl;
std::cout << g_server.execute("foobar\n") << std::endl;
std::cout << g_server.execute("dog\n") << std::endl;
}
The problem is that the client only receives the massage "error", so the std::cin of the server seems to be broken.
My question is, what did I do wrong?
You're disabling inheritance for the handle that the child will use to read from stdin - the child needs to inherit that handle. Instead of:
SetHandleInformation(m_ri, HANDLE_FLAG_INHERIT, 0);
Try the following to disable inheritance on the handle that the server process will use to write to the child's stdin:
SetHandleInformation(m_wi, HANDLE_FLAG_INHERIT, 0);