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
Related
I have a C++ console application which forks itself and closes the main process.
std::cin in the childprocess is not blocking anymore if a press any key. This results in an endless loop. If I don't fork before then the application behaves as expected.
I have tried different combinations of cin::ignore, cin::fail, cin::clear and close to get this fixed but without success.
I'm using Ubuntu 18.04.
Why this is happening and how can I fix that?
/* includes */
#include <iostream>
#include <unistd.h>
#include <limits>
void fork_to_background()
{
pid_t f_return = fork();
if (f_return == -1)
{
exit(1);
}
if (f_return != 0)
{
exit(0);
}
}
int main(int argc, char** argv)
{
fork_to_background();
std::string commands;
while(true)
{
std::cin >> commands;
std::cout << "Loop" << std::endl;
//std::cin.clear();
//std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
std::cin >> commands; does not block when you reach EOF, you can see it checking if >> success, for instance
if (! std::cin >> commands) {
std::cout << "EOF" << std::endl;
break;
}
the two lines you put in comment are useless here because you read a string, they are useful in case you read for instance a number and the input is not a valid number
note the parent process exit immediately after the fork, closing stdin for the child because they share stdin
if I modify your program to have :
/* includes */
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
#include <limits>
#include <sys/wait.h>
void fork_to_background()
{
pid_t f_return = fork();
if (f_return == -1)
{
exit(1);
}
if (f_return != 0)
{
waitpid(f_return, NULL, 0); // wait end of child
exit(0);
}
}
int main(int argc, char** argv)
{
fork_to_background();
std::string commands;
while(std::cin >> commands)
{
std::cout << commands << std::endl;
std::cout << "Loop" << std::endl;
}
std::cout << "done" << std::endl;
}
Compilation and execution :
/tmp % g++ -Wall f.cc
/tmp % echo "aze qsd" | ./a.out
aze
Loop
qsd
Loop
done
/tmp %
I have a case where I need pipe the output of a child process to an ifstream.
I am trying both creating an ifstream from a file descriptor using the method here: How to construct a c++ fstream from a POSIX file descriptor?
and I am also trying to just use a pipe from the child stderr to my own stdin and using cin as my stream.
In both cases I am getting -1 when I call tellg.
Here is my code with the pipe from child stderr to parent stdin:
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
using namespace std;
int
main()
{
int mypipe[2];
pipe(mypipe);
dup2(mypipe[0], STDIN_FILENO);
dup2(mypipe[1], STDERR_FILENO);
__pid_t pid = fork();
if(pid == 0)
{
// this is a process that outputs stuff into std::err
char* argv[] = {"copy-feats", nullptr};
int ret = execvp(argv[0], argv);
exit(ret);
}
int status;
waitpid(pid, &status, WNOHANG);
cin.clear(); // attempting to clear the error state. Not working.
long size = cin.tellg();
cout << size << endl;
}
so as I said the output of tellg is -1.
thought if I try to use getline(cin, some_string) I'll actually be able to see the output of the child program.
I tried creating a stream from a pipe, but it still gives me -1.
Here's the code I used:
#include <iostream>
#include <fstream>
#include <ext/stdio_filebuf.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#define READ_FD 0
#define WRITE_FD 1
using namespace std;
using FilebufType = __gnu_cxx::stdio_filebuf<std::ifstream::char_type>;
int
main()
{
int mypipe[2];
pipe(mypipe);
__pid_t pid = fork();
if(pid == 0)
{
dup2(mypipe[WRITE_FD], STDERR_FILENO);
char* argv[] = {"copy-feats", nullptr};
int ret = execvp(argv[0], argv);
exit(ret);
}
int status;
waitpid(pid, &status, WNOHANG);
FilebufType filebuf(mypipe[READ_FD], std::ios::in);
istream is(&filebuf);
is.clear();
auto size = is.tellg();
cout << size << endl;
}
Thanks in advance.
In practice tellg() returns an actual file position only when the input stream is a real file. That is, when the input stream is a std::ifstream, and then only when the underlying file is a plain file.
Pipes, and other non-plain files don't have a concept of a file position.
On Linux, which you are using, tellg() is typically implemented (indirectly, but that's not relevant here) by using lseek(2), and lseek(2)'s documentation explicitly specifies that it returns an ESPIPE error if the file descriptor is a pipe. And an error return, eventually, translates to tellg() returning -1.
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 am trying to to fork my c++ program and direct the parents output into the childs input, I am using pipe() and fork(). In the directory of the program there is a file called input.txt. Unfortunately the only output I get is "wc: stdin: read: Bad file descriptor". Does anyone know why this is? If so what am I doing wrong? Thanks
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
int main(int argc, char *argv[]){
int pipes[2],pid,stdIn,stdOut;
stdIn = dup(0);
stdOut = dup(1);
pipe(pipes);
pid = fork();
if(pid == 0){
dup2(pipes[1],0);
close(pipes[1]);
execlp("wc","wc",NULL);
}
else{
dup2(pipes[0],1);
close(pipes[0]);
std::cout<<"input.txt"<<std::endl;
dup2(stdOut,0);
std::cout<<"parent done\n";
wait(NULL);
}
std::cout<<"after"<<std::endl;
return 0;
}
There are several things that should be fixed in your program:
Use STDIN_FILENO and STDOUT_FILENO instead of 0 and 1. This values may change on different platforms and you have also made a mistake which could probably be avoided if you've used names instead of value, e.g. dup2(stdOut,0); duplicated stdin and you need to duplicate stdout here.
You should close write end of the pipe in both child and parent.
By making wc read from stdin, you are then passing "input.txt" string to it - it will return stats for that string, not for the file. You could either fix it be opening a file descriptor for that file or using exec* with cat.
None of your calls the functions like pipe() or execlp() checks for failure. You should do it like that:
if (pipe(pipes) == -1) {
perror("pipe");
exit(1);
}
You don't need stdIn variable.
You will find fixed code below (it does not implement what I've described in the (5) though):
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int pipes[2], pid, stdOut;
stdOut = dup(STDOUT_FILENO);
pipe(pipes);
pid = fork();
if (pid == 0) {
dup2(pipes[0], STDIN_FILENO);
/* You need to close write end of the pipe here */
close(pipes[1]);
execlp("wc", "wc", NULL);
} else {
std::cout << "Parent setup" << std::endl;
dup2(pipes[1], STDOUT_FILENO);
/* You need to close write end of the pipe here as well */
close(pipes[1]);
/* This will only send the string "input.txt" through the pipe, to the
* wc command */
std::cout << "input.txt" << std::endl;
dup2(stdOut, STDOUT_FILENO);
std::cout << "Parent done" << std::endl;
wait(NULL);
}
std::cout << "Program finished" << std::endl;
return 0;
}
EDIT: As suggested in the comment to the other answer, you could simple use xargs wc to read stdint as file argument:
execlp("xargs", "xargs","wc",NULL);
You have the pipe backwards, you have connected the write end of the pipe to the standard input of wc. You will need to close the write end of the pipe in both processes before wc will detect an end of file condition and terminate normally.
You also incorrectly restore the original standard output to the standard input of the parent.
Furthermore wc will by default not interpret standard input as a list filenames and will therefore not read input.txt.
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