How to set PTY (Pseudo Terminal) to NON-ECHOING Unix in C / C++ [duplicate] - c++

On linux, I am opening a pseudo tty on the master side. While there is no client on the slave side, the pseudo tty seems to be echoing everything I am writing to him, which is not what I am expecting.
Consider the folowing code :
int main(int argc, char * argv[])
{
int ptyfd;
int rc; /* return code */
char readbuf[3];
ptyfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
die_on_error(ptyfd, "open ptmx");
/* unlock and print slave name */
rc = unlockpt(ptyfd);
die_on_error(rc, "unlockpt");
printf("Slave pts name : %s\n", ptsname(ptyfd));
write(ptyfd, "C", 1);
rc=read(ptyfd, readbuf, 1);
die_on_error(rc, "read");
printf("read returned %c\n",readbuf[0]);
return 0;
}
When I run this program, I would expect the read call to block, but instead it immediately returns and the readbuf content is C. How can I change this behaviour ? When the slave side is not opened, I would like the character written on the master side to either vanish or be fifoed for later reading by the slave side.
Is changing the master side attributes the right way to do it ?

I thought the master side was not a tty, but apparently it is, so you can call things like tcgettattr and tcsetattr, and suppress the echo.

None of the older answers provided the correct C code, so here it is:
struct termios tmios;
tcgetattr(ptfd, &tmios);
tmios.c_lflag &= ~(ECHO);
tcsetattr(ptfd, TCSANOW, &tmios);

You can use the blocking getch() call. Also getch() will not echo the content.

Related

linux pseudo terminal (open select read)

I have a following scenario: Someone creates a pseudo terminal via opening /dev/ptmx. New terminal is created and named for example /dev/pts/2. Then, in my program I open /dev/pts/2 for reading. But I also open other devices for reading and use select() function to wait for any incoming data. The select have also some timeout specified for performing other stuff when no data arrives for too long. After successful select i read data using read() function and then print it on the screen.
I encountered an issue if the pseudo terminal is closed by the one who created it. In this case select function ends immediately indicating success as well as read ends indicating "no data" by returning zero. The issue imho is that neither select nor read returns error in such case. How should I handle this to detect that the terminal is no longer existing?
Status processData()
{
fd_set readFileDescriptorSet; // defined somewhere else
int maxFileDescriptor; // defined somewhere else
struct timeval timeout; // defined somewhere else
int ret = select(maxFileDescriptor + 1, &readFileDescriptorSet, nullptr, nullptr, &timeout);
if (!ret) // timeout
return Status::success();
if (ret < 0) // error from select()
return Status::error("select error");
ssize_t rd;
char buff[10];
do {
rd = read(interfaces.serialPort.getFileDescriptor(), buff, sizeof(buff) - 1);
if (rd > 0) { // some data has been read
buff[rd] = '\0';
std::cout << buff;
}
} while (rd > 0);
if (rd < 0) // error from read()
return Status::error("read error");
return Status::success();
}
While the way I open the pseudo terminal is following:
Status internalOpen(std::string fileName)
{
close();
fileDescriptor = ::open(fileName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fileDescriptor == -1)
return Status::error("Terminal::internalOpen::open('" + fileName + "')");
struct termios attributes;
if (tcgetattr(fileDescriptor, &attributes))
return Status::error("Terminal::internalOpen::tcgetattr()");
setAttributes(attributes);
if (tcsetattr(fileDescriptor, TCSANOW, &attributes))
return Status::error("Terminal::internalOpen::tcsetattr()");
return Status::success();
}
void setAttributes(struct termios &attributes)
{
cfmakeraw(&attributes);
cfsetspeed(&attributes, Config::baudRate);
attributes.c_iflag &= ~(IXOFF | IXANY);
attributes.c_oflag &= ~(ONLCR);
attributes.c_lflag &= ~(ECHOE);
attributes.c_cflag &= ~(CSTOPB | CRTSCTS);
attributes.c_cflag |= CREAD | CLOCAL;
attributes.c_cc[VMIN] = 0;
attributes.c_cc[VTIME] = 0;
}
After select() returns indicating that there's something to be read, the shown code loops repeatedly trying to read() from the non-blocking file descriptor until it is 0:
do {
rd = read( ...
} while (rd > 0);
That's certainly reasonable. Except that the closed connection results in the very first read() returning 0, which the shown logic cannot discriminate.
All that's really needed here is to keep track of whether anything has been read, prior read() returning 0. But if read() returned 0 right off the bat, your goose is cooked.
Additionally, there a few other improvements will make things more robust.
After select() returns, actually check if the file descriptor's bit remains set in the readFileDescriptorSet. The shown logic simply assumes that it is, by checking for all other possibilities. Still, this is somewhat fragile. It's easy to forget this assumption if something tangentially related gets modified (i.e., another fle descriptor gets thrown into the mix).
Use poll() instead of select(), and explicitly check for POLLHUP|POLLRDHUP in revents. The file descriptor closure condition is more explicitly called out, in the poll() interface.

C++ redirect or disable stdio temporarily

In our C++ project under MacOS X, we are using stdio for interaction with clients. Yet, the dylib we are using is also using stdio to print "open log files". This breaks down all communication between our clients and the application. I looked at the examples of redirecting stdio to a file or temporarily disabling stdio. Yet, we could not succeed in it.
So, how can we disable or redirect stdio temporarily while interacting with the dylib.
void RedirectStandardStreamsToDEVNULL(int *_piOriginalSTDIN_FILENO, int *_piOriginalSTDOUT_FILENO, int *_piOriginalSTDERR_FILENO)
{
//flushing pending things before redirection.
//fflush(stdin);
fflush(stdout);
fflush(stderr);
*_piOriginalSTDIN_FILENO = dup(STDIN_FILENO);
*_piOriginalSTDOUT_FILENO = dup(STDOUT_FILENO);
*_piOriginalSTDERR_FILENO = dup(STDERR_FILENO);
int devnull = open("/dev/null", O_RDWR);
dup2(devnull, STDIN_FILENO);
dup2(devnull, STDOUT_FILENO);
dup2(devnull, STDERR_FILENO);
close(devnull);
}
void RestoreStandardStreams(int *_piOriginalSTDIN_FILENO, int *_piOriginalSTDOUT_FILENO, int *_piOriginalSTDERR_FILENO)
{
//flushing pending things before restoring.
//fflush(stdin);
fflush(stdout);
fflush(stderr);
dup2(*_piOriginalSTDIN_FILENO, STDIN_FILENO);
dup2(*_piOriginalSTDOUT_FILENO, STDOUT_FILENO);
dup2(*_piOriginalSTDERR_FILENO, STDERR_FILENO);
}
void myfunction()
{
int iOriginalSTDIN_FILENO = -1;
int iOriginalSTDOUT_FILENO = -1;
int iOriginalSTDERR_FILENO = -1;
RedirectStandardStreamsToDEVNULL(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO);
//all of your code which prints to stdout or stderr will be directed to /dev/null
RestoreStandardStreams(&iOriginalSTDIN_FILENO, &iOriginalSTDOUT_FILENO, &iOriginalSTDERR_FILENO);
}
Important point is to identify the functions which are called inside dylib from your code. Now, surround such functions with Redirect and Restore functions described above.
OSX is a POSIX systems, and like all POSIX systems standard output is file descriptor STDOUT_FILENO (which is a macro defined as 1).
What you can do is duplicate STDOUT_FILENO to another file descriptor, open a temporary file and duplicating (using dup2) the temporary file as STDOUT_FILENO. Then whenever there is output to standard out (using plain write, C printf or C++ std::cout) it will be put in the temporary file.
When done with the temporary "redirection" you simply duplicate the saved standard output (from the first dup call) back into STDOUT_FILENO. and close and remove the temporary file.
Something like the following:
int saved_stdout = dup(STDOUT_FILENO);
int temp_file = open("/tmp/temp_stdout", O_WRONLY, 0600);
dup2(temp_file, STDOUT_FILENO); // Replace standard out
// Code here to write to standard output
// It should all end up in the file /tmp/temp_stdout
dup2(saved_stdout, STDOUT_FILENO); // Restore old standard out
close(temp_file)
unlink("/tmp/temp_stdout"); // Remove file

Check keyboard input without stopping flow of loop [duplicate]

How do you do nonblocking console IO on Linux/OS X in C?
I want to add an example:
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
char buf[20];
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
sleep(4);
int numRead = read(0, buf, 4);
if (numRead > 0) {
printf("You said: %s", buf);
}
}
When you run this program you have 4 seconds to provide input to standard in. If no input found, it will not block and will simply return.
2 sample executions:
Korays-MacBook-Pro:~ koraytugay$ ./a.out
fda
You said: fda
Korays-MacBook-Pro:~ koraytugay$ ./a.out
Korays-MacBook-Pro:~ koraytugay$
Like Pete Kirkham, I found cc.byexamples.com, and it worked for me. Go there for a good explanation of the problem, as well as the ncurses version.
My code needed to take an initial command from standard input or a file, then watch for a cancel command while the initial command was processed. My code is C++, but you should be able to use scanf() and the rest where I use the C++ input function getline().
The meat is a function that checks if there is any input available:
#include <unistd.h>
#include <stdio.h>
#include <sys/select.h>
// cc.byexamples.com calls this int kbhit(), to mirror the Windows console
// function of the same name. Otherwise, the code is the same.
bool inputAvailable()
{
struct timeval tv;
fd_set fds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
return (FD_ISSET(0, &fds));
}
This has to be called before any stdin input function When I used std::cin before using this function, it never returned true again. For example, main() has a loop that looks like this:
int main(int argc, char* argv[])
{
std::string initialCommand;
if (argc > 1) {
// Code to get the initial command from a file
} else {
while (!inputAvailable()) {
std::cout << "Waiting for input (Ctrl-C to cancel)..." << std::endl;
sleep(1);
}
std::getline(std::cin, initialCommand);
}
// Start a thread class instance 'jobThread' to run the command
// Start a thread class instance 'inputThread' to look for further commands
return 0;
}
In the input thread, new commands were added to a queue, which was periodically processed by the jobThread. The inputThread looked a little like this:
THREAD_RETURN inputThread()
{
while( !cancelled() ) {
if (inputAvailable()) {
std::string nextCommand;
getline(std::cin, nextCommand);
commandQueue.lock();
commandQueue.add(nextCommand);
commandQueue.unlock();
} else {
sleep(1);
}
}
return 0;
}
This function probably could have been in main(), but I'm working with an existing codebase, not against it.
For my system, there was no input available until a newline was sent, which was just what I wanted. If you want to read every character when typed, you need to turn off "canonical mode" on stdin. cc.byexamples.com has some suggestions which I haven't tried, but the rest worked, so it should work.
You don't, really. The TTY (console) is a pretty limited device, and you pretty much don't do non-blocking I/O. What you do when you see something that looks like non-blocking I/O, say in a curses/ncurses application, is called raw I/O. In raw I/O, there's no interpretation of the characters, no erase processing etc. Instead, you need to write your own code that checks for data while doing other things.
In modern C programs, you can simplify this another way, by putting the console I/O into a thread or lightweight process. Then the I/O can go on in the usual blocking fashion, but the data can be inserted into a queue to be processed on another thread.
Update
Here's a curses tutorial that covers it more.
I bookmarked "Non-blocking user input in loop without ncurses" earlier this month when I thought I might need non-blocking, non-buffered console input, but I didn't, so can't vouch for whether it works or not. For my use, I didn't care that it didn't get input until the user hit enter, so just used aio to read stdin.
Here's a related question using C++ -- Cross-platform (linux/Win32) nonblocking C++ IO on stdin/stdout/stderr
Another alternative to using ncurses or threads is to use GNU Readline, specifically the part of it that allows you to register callback functions. The pattern is then:
Use select() on STDIN (among any other descriptors)
When select() tells you that STDIN is ready to read from, call readline's rl_callback_read_char()
If the user has entered a complete line, rl_callback_read_char will call your callback. Otherwise it will return immediately and your other code can continue.
Let`s see how it done in one of Linux utilites. For example, perf/builtin-top.c sources (simplified):
static void *display_thread(void *arg)
{
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
struct termios save;
set_term_quiet_input(&save);
while (!done) {
switch (poll(&stdin_poll, 1, delay_msecs)) {
...
}
}
tcsetattr(0, TCSAFLUSH, &save);
}
So, if you want to check if any data available, you can use poll() or select() like this:
#include <sys/poll.h>
...
struct pollfd pfd = { .fd = 0, .events = POLLIN };
while (...) {
if (poll(&pfd, 1, 0)>0) {
// data available, read it
}
...
}
In this case you will receive events not on each key, but on whole line, after [RETURN] key is pressed. It's because terminal operates in canonical mode (input stream is buffered, and buffer flushes when [RETURN] pressed):
In canonical input processing mode, terminal input is processed in
lines terminated by newline ('\n'), EOF, or EOL characters. No input
can be read until an entire line has been typed by the user, and the
read function (see Input and Output Primitives) returns at most a
single line of input, no matter how many bytes are requested.
If you want to read characters immediately, you can use noncanonical mode. Use tcsetattr() to switch:
#include <termios.h>
void set_term_quiet_input()
{
struct termios tc;
tcgetattr(0, &tc);
tc.c_lflag &= ~(ICANON | ECHO);
tc.c_cc[VMIN] = 0;
tc.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &tc);
}
Simple programm (link to playground):
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <termios.h>
void set_term_quiet_input()
{
struct termios tc;
tcgetattr(0, &tc);
tc.c_lflag &= ~(ICANON | ECHO);
tc.c_cc[VMIN] = 0;
tc.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &tc);
}
int main() {
struct pollfd pfd = { .fd = 0, .events = POLLIN };
set_term_quiet_input();
while (1) {
if (poll(&pfd, 1, 0)>0) {
int c = getchar();
printf("Key pressed: %c \n", c);
if (c=='q') break;
}
usleep(1000); // Some work
}
}
Not entirely sure what you mean by 'console IO' -- are you reading from STDIN, or is this a console application that reads from some other source?
If you're reading from STDIN, you'll need to skip fread() and use read() and write(), with poll() or select() to keep the calls from blocking. You may be able to disable input buffering, which should cause fread to return an EOF, with setbuf(), but I've never tried it.

Communication between pipes in linux

I have two functions writer() and reader(). I am writing message into the pipe from writer() function and reading it from the reader() function. The problem I am facing is that message is being written in the pipe, but it's not getting read. Maybe there is problem in opening pipe for reading. The code is:
#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
using namespace std;
//edit
int fifo = mkfifo("/tmp/mypipe", S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
void writer()
{
char message[] = "this is a message";
int fd;
fd = open("pipe" , O_WRONLY);
write(fd , message , sizeof(message));
cout<<"message wrote: "<<message<<"\n"; // gives output
} // message wrote: this is a message
void reader()
{
char buffer[100];
int fd;
fd = open("pipe" , O_RDONLY);
read(fd , buffer , 100);
cout<<"message is: "<<buffer<<"\n"; // gives output
} // message is:
int main()
{
writer();
reader();
return 0;
}
I've debugged it, and I think the problem is, fifo is not being created correctly. I don't know how to resolve this. Need more help.
Thank you for any help.
My guess is that you have not created the pipe in a correct way. Take a look at the mkfifo man page. For the umask value take a look at the umask man page.
something like mkfifo("/tmp/pipe", 0666), before you open /tmp/pipe in the reader/writer.
Also take a look at the fifo man page:
The kernel maintains exactly one pipe object for each FIFO special
file that is opened by at least one process. The FIFO must be opened
on both ends (reading and writing) before data can be passed.
Normally, opening the FIFO blocks until the other end is opened also.
So your problem now is, that the open(..., O_WRONLY) blocks until the reader opens the file.
To try it out, let just the reader run and then use echo "test" > /tmp/pipe.
Update:
Or use threads, i just tried it out.
int main() {
mkfifo(fifo_name.c_str(), 0666);
std::thread w(writer);
std::thread r(reader);
w.join();
r.join();
unlink(fifo_name.c_str());
return 0;
}
you also have to #include <thread>, add this compiler flag: -std=c++0x and add the following library to the linker: -lpthread.
Be sure to check returns from function calls, since they can tell you what the problem is.
Include errno.h:
#include <errno.h>
#include <string.h>
And check errno when you get an error return from your write or read open attempt:
fd = open("pipe" , O_WRONLY);
if (fd < 0)
{
cout << "writer open failed: " << errno << "(" << strerror(errno) << ")\n";
/* exit */
}
As another answer states, you're not using mkfifo(), so you're making a typical file (which would also work but may fail if you don't provide O_CREAT and a mode argument).
It is about how named pipe work in posix. You can only write in it, if there is already somebody, who is reading from it. If there is none, your write() operation will be blocked until somebody don't read.
The simplest solution were, if
You used nonblocking I/O
You implemented the reader and the writer in different processes (threads) and called the reader before the writer.

popen simultaneous read and write [duplicate]

This question already has answers here:
Can popen() make bidirectional pipes like pipe() + fork()?
(6 answers)
Closed 3 years ago.
Is it possible to read and write to a file descriptor returned by popen. I have an interactive process I'd like to control through C. If this isn't possible with popen, is there any way around it?
As already answered, popen works in one direction. If you need to read and write, You can create a pipe with pipe(), span a new process by fork() and exec functions and then redirect its input and outputs with dup2(). Anyway I prefer exec over popen, as it gives you better control over the process (e.g. you know its pid)
EDITED:
As comments suggested, a pipe can be used in one direction only. Therefore you have to create separate pipes for reading and writing. Since the example posted before was wrong, I deleted it and created a new, correct one:
#include<unistd.h>
#include<sys/wait.h>
#include<sys/prctl.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
int main(int argc, char** argv)
{
pid_t pid = 0;
int inpipefd[2];
int outpipefd[2];
char buf[256];
char msg[256];
int status;
pipe(inpipefd);
pipe(outpipefd);
pid = fork();
if (pid == 0)
{
// Child
dup2(outpipefd[0], STDIN_FILENO);
dup2(inpipefd[1], STDOUT_FILENO);
dup2(inpipefd[1], STDERR_FILENO);
//ask kernel to deliver SIGTERM in case the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM);
//replace tee with your process
execl("/usr/bin/tee", "tee", (char*) NULL);
// Nothing below this line should be executed by child process. If so,
// it means that the execl function wasn't successfull, so lets exit:
exit(1);
}
// The code below will be executed only by parent. You can write and read
// from the child using pipefd descriptors, and you can send signals to
// the process using its pid by kill() function. If the child process will
// exit unexpectedly, the parent process will obtain SIGCHLD signal that
// can be handled (e.g. you can respawn the child process).
//close unused pipe ends
close(outpipefd[0]);
close(inpipefd[1]);
// Now, you can write to outpipefd[1] and read from inpipefd[0] :
while(1)
{
printf("Enter message to send\n");
scanf("%s", msg);
if(strcmp(msg, "exit") == 0) break;
write(outpipefd[1], msg, strlen(msg));
read(inpipefd[0], buf, 256);
printf("Received answer: %s\n", buf);
}
kill(pid, SIGKILL); //send SIGKILL signal to the child process
waitpid(pid, &status, 0);
}
The reason popen() and friends don't offer bidirectional communication is that it would be deadlock-prone, due to buffering in the subprocess. All the makeshift pipework and socketpair() solutions discussed in the answers suffer from the same problem.
Under UNIX, most commands cannot be trusted to read one line and immediately process it and print it, except if their standard output is a tty. The reason is that stdio buffers output in userspace by default, and defers the write() system call until either the buffer is full or the stdio stream is closed (typically because the program or script is about to exit after having seen EOF on input). If you write to such a program's stdin through a pipe, and now wait for an answer from that program's stdout (without closing the ingress pipe), the answer is stuck in the stdio buffers and will never come out - This is a deadlock.
You can trick some line-oriented programs (eg grep) into not buffering by using a pseudo-tty to talk to them; take a look at libexpect(3). But in the general case, you would have to re-run a different subprocess for each message, allowing to use EOF to signal the end of each message and cause whatever buffers in the command (or pipeline of commands) to be flushed. Obviously not a good thing performance-wise.
See more info about this problem in the perlipc man page (it's for bi-directional pipes in Perl but the buffering considerations apply regardless of the language used for the main program).
You want something often called popen2. Here's a basic implementation without error checking (found by a web search, not my code):
// http://media.unpythonic.net/emergent-files/01108826729/popen2.c
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "popen2.h"
int popen2(const char *cmdline, struct popen2 *childinfo) {
pid_t p;
int pipe_stdin[2], pipe_stdout[2];
if(pipe(pipe_stdin)) return -1;
if(pipe(pipe_stdout)) return -1;
//printf("pipe_stdin[0] = %d, pipe_stdin[1] = %d\n", pipe_stdin[0], pipe_stdin[1]);
//printf("pipe_stdout[0] = %d, pipe_stdout[1] = %d\n", pipe_stdout[0], pipe_stdout[1]);
p = fork();
if(p < 0) return p; /* Fork failed */
if(p == 0) { /* child */
close(pipe_stdin[1]);
dup2(pipe_stdin[0], 0);
close(pipe_stdout[0]);
dup2(pipe_stdout[1], 1);
execl("/bin/sh", "sh", "-c", cmdline, NULL);
perror("execl"); exit(99);
}
childinfo->child_pid = p;
childinfo->to_child = pipe_stdin[1];
childinfo->from_child = pipe_stdout[0];
close(pipe_stdin[0]);
close(pipe_stdout[1]);
return 0;
}
//#define TESTING
#ifdef TESTING
int main(void) {
char buf[1000];
struct popen2 kid;
popen2("tr a-z A-Z", &kid);
write(kid.to_child, "testing\n", 8);
close(kid.to_child);
memset(buf, 0, 1000);
read(kid.from_child, buf, 1000);
printf("kill(%d, 0) -> %d\n", kid.child_pid, kill(kid.child_pid, 0));
printf("from child: %s", buf);
printf("waitpid() -> %d\n", waitpid(kid.child_pid, NULL, 0));
printf("kill(%d, 0) -> %d\n", kid.child_pid, kill(kid.child_pid, 0));
return 0;
}
#endif
popen() can only open the pipe in read or write mode, not both. Take a look at this thread for a workaround.
In one of netresolve backends I'm talking to a script and therefore I need to write to its stdin and read from its stdout. The following function executes a command with stdin and stdout redirected to a pipe. You can use it and adapt it to your liking.
static bool
start_subprocess(char *const command[], int *pid, int *infd, int *outfd)
{
int p1[2], p2[2];
if (!pid || !infd || !outfd)
return false;
if (pipe(p1) == -1)
goto err_pipe1;
if (pipe(p2) == -1)
goto err_pipe2;
if ((*pid = fork()) == -1)
goto err_fork;
if (*pid) {
/* Parent process. */
*infd = p1[1];
*outfd = p2[0];
close(p1[0]);
close(p2[1]);
return true;
} else {
/* Child process. */
dup2(p1[0], 0);
dup2(p2[1], 1);
close(p1[0]);
close(p1[1]);
close(p2[0]);
close(p2[1]);
execvp(*command, command);
/* Error occured. */
fprintf(stderr, "error running %s: %s", *command, strerror(errno));
abort();
}
err_fork:
close(p2[1]);
close(p2[0]);
err_pipe2:
close(p1[1]);
close(p1[0]);
err_pipe1:
return false;
}
https://github.com/crossdistro/netresolve/blob/master/backends/exec.c#L46
(I used the same code in Can popen() make bidirectional pipes like pipe() + fork()?)
Use forkpty (it's non-standard, but the API is very nice, and you can always drop in your own implementation if you don't have it) and exec the program you want to communicate with in the child process.
Alternatively, if tty semantics aren't to your liking, you could write something like forkpty but using two pipes, one for each direction of communication, or using socketpair to communicate with the external program over a unix socket.
You can't use popen to use two-way pipes.
In fact, some OSs don't support two-way pipes, in which case a socket-pair (socketpair) is the only way to do it.
popen works for me in both directions (read and write)
I have been using a popen() pipe in both directions..
Reading and writing a child process stdin and stdout with the file descriptor returned by popen(command,"w")
It seems to work fine..
I assumed it would work before I knew better, and it does.
According posts above this shouldn't work.. which worries me a little bit.
gcc on raspbian (raspbery pi debian)