Terminate cat command immediately after using in C - c

So I am communicating with a device by using echo to send and cat to receive. Here's a snippet of my code:
fp = popen("echo "xyz" > /dev/ttyACM0 | cat - /dev/ttyACM0", "r");
while (fgets(ret_val, sizeof(ret_val)-1, fp) != NULL)
{
if (strcmp(ret_val, "response") == 0)
{
close(fp);
return ret_val;
}
}
Ok, The problem is, cat seems to stay open, because when I run this code in a loop, it works the first time, then hangs at the spot I call popen. Am I correct in assuming cat is the culprit?
Is there a way to terminate cat as soon as I run the command, so I just get the response from my device? Thanks!

In the command:
echo "xyz" > /dev/ttyACM0 | cat - /dev/ttyACM0
TTY devices normally do not open until carrier is present, or CLOCAL is set. The cat could be waiting on open. Assuming the device opens, then the cat will hang waiting to read characters until either (1) it receives an EOF character such as control-D, or (2) carrier is lost or (3) you kill it.
Another problem here is that the pipe between echo and cat immediately closes, because the output of the echo is redirected to the same TTY device, and the redirection closes the pipe.
Generally TTY devices are ornery beasts and require special handling to get the logic right. Probably you are better to read up on TTY devices especially:
man termios
If you are doing something REALLY SIMPLE, you might get by with:
fp = popen("echo 'xyz' >/dev/ttyACM0 & (read x; echo \"$x\")");
Keep in mind that both the echo and the read might hang waiting for carrier and that you will get at most one line of output from the popen, and the read could hang waiting for an EOL character.
This whole approach is fraught with problems. TTY devices require delicate care. You are using a hammer in the dark.

There's no easy way to kill the process launched by popen, as there's no API to get the pid -- there's only pclose which waits until it ends of its own account (and youe should ALWAYS use pclose instead of fclose to close a FILE * opened by popen.)
Instead, you're probably better off not using popen at all -- just use fopen and write what you want with fputs:
fp = fopen("/dev/ttyACM0", "r+");
fputs("xyz\n", fp); // include the newline explicitly
fflush(fp); // always flush after writing before reading
while (fgets(ret_val, sizeof(ret_val)-1, fp) != NULL) {
:

Related

C & bash redirection processus communication

look at this bash :
mkfifo fifo
./processA <fifo | processB >fifo
In my process A, i generate a file which is send by process B. Then I want to process the result of processB.
So in A I just send info to B with printfs into std out. Then I create a thread who just read(stdin). After creating this thread, I send infos to B via printf.
I do not understand why this whole sh block. The read never recieive anything. Why? the two process are tested and work fine separatly. The whole sh also work perfectly (dont block) if I dont read (but then I cant process B output).
Can somebody explain me what i am understanding wrong?
Sorry for my approximative English. I am also intersted by your clean solution if you have one (but it would prefer understanding why this one is not working).
//edit
Here is the main (process A):
//managing some arguments threatment, constructing object...
pthread_t thread;//creation of the thread supposed to read
if(pthread_create(&thread, NULL,IsKhacToolKit::threadRead, solver) != 0) {
fprintf(stderr,"\nSomething went wrong while creating Reader thread\n" );
}
solver->generateDimacFile();//printing to stdout
pthread_exit(0);
}
the function executed by the thread is just supposed to read stdin and printing into stderr the string obtened (for now). Nothing is printed in stderr right now.
generateDimacFile print a char* into stdout (and flush(stdout) at the end) that processB use. The process B is that one: http://www.labri.fr/perso/lsimon/glucose/
here ise the function executed by the thread now :
char* satResult=(char*)malloc(sizeof(char)* solutionSize);
for (int i=0; i<2; i++){
read(0, satResult, solutionSize );
fprintf(stderr, "\n%s\n", satResult);
}
DEBUGFLAG("Getting result from glucose");
Ok so now thanks to Maxim Egorushkin, I discovered that the first read dont block, but the next one block using that bash instead:
./processA <fifo | stdbuf -o0 ./processB >fifo
and if I use that one :
stdbuf -o0 ./processA <fifo | stdbuf -o0 ./processB >fifo
Most of the time I can read twice whitout blocking (some time it block). I still can't read 3 times. I dont understand why it change anything because I flush stdout in generateDimacFile.
Look at what's actually printed when it dont block(reading twice) in stderr:
c
c This is glucose 4.0 -- based on MiniSAT (Many thanks to MiniSAT team)
c
c This is glucose 4.0 -- based on MiniSAT (Many thanks to MiniSAT team)
c
c Reading from standard input... Use '--help' for help.
s to MiniSAT team)
c
The coresponding expected result:
c
c This is glucose 4.0 -- based on MiniSAT (Many thanks to MiniSAT team)
c
c Reading from standard input... Use '--help' for help.
c | |
s UNSATISFIABLE
You have a potentially blocking race condition. If the processB needs to read a large amount of data before it produces anything, then it is possible that processA will be data starved before it produces enough data. Once that happens, there's a deadlock. Or, if processA never generates any data until it reads something, then both processes will just sit there. It really depends on what processA and processB are doing.
If the processes are sufficiently simple, what you are doing should work. For instance:
$ cat a.sh
#!/bin/sh
echo "$$"
while read line; do echo $(($line + 1 )); echo $$ read: $line >&2; sleep 1; done
$ ./a.sh < fifo | ./a.sh > fifo
26385 read: 26384
26384 read: 26385
26385 read: 26386
26384 read: 26385
26385 read: 26386
26384 read: 26387
26385 read: 26388
26384 read: 26387
^C
Using | or > in bash makes the process block-buffered, so that it does not output anything until the buffer is full or fflush is invoked.
Try disabling all buffering with stdbuf -o0 ./processA <fifo | stdbuf -o0 processB >fifo.
stderr does not get redirected in your command line, I am not sure why you write into it. Write into stdout.
Another issue is that
read(0, satResult, solutionSize);
fprintf(stderr, "\n%s\n", satResult);
is incorrect, satResult is not zero-terminated and the errors are not handled. A fixL
ssize_t r = read(0, satResult, solutionSize);
if(r > 0)
fwrite(satResult, r, 1, stdout);
else
// Handle read error.

Buffering while popen working

I'm using the following command to get a constant output of a two digit value:
pipe = popen("hcidump -a | egrep --line-buffered 'RSSI|bdaddr' | grep -A1 --line-buffered --no-group-separator 'bdaddr 78:A5:04:17:9F:66' | grep -Po --line-buffered 'RSSI:\\s+\\K.*'", "r");
I want to buffer that, so I can transform it into a integer value and work with it. but I'm not sure how to achieve that. As long as I have popen running my C-programm will not go on. I checked it with strace and he will read the value in popen and will not termit.
the rest of the code looks like that:
if (pipe)
{
printf("entered pipe-if");
while(!feof(pipe))
{
if(fgets(buffer, 128, pipe) != NULL){}
}
pclose(pipe);
printf("pclose");
buffer[strlen(buffer)-1] = '\0';
}
The idea behind it is that I want to use the Data to calculate a distnace in "realtime". A possibility would be that I could tell popen to end the process after x seconds, then use the buffered data and then start the process from the beginning.
Thanks for help and advice.
After using popen to open the pipe you should work with the file descriptor rather than the FILE pointer. You can then turn the file to non-blocking and process the data as it comes in.
int fd = fileno(pipe);
fcntl(fd, F_SETFL, O_NONBLOCK);
Then you can read data from the pipe using
bytes = read(fd, buf, bufsize);
If bytes is greater than 0, then you have some more data to process. If bytes is -1 and errno is EAGAIN, then there's nothing in the pipe. Anything else you're done. You'll have to deal with the data however it comes in (ie you don't get fgets() nicely doing things per-line)

Suppress output from popen()

Is there a way to suppress the output from popen() without losing the Wait().
Test 1:
FILE * stream = NULL;
char buffer [120];
stream = popen ("ffmpeg -y -i test.amr -ar 16000 test.wav -v quiet", "r");
while (fgets (buffer, sizeof(buffer), stream))
{
}
pclose (stream);
Test 2:
FILE * stream = NULL;
char buffer [120];
stream = popen ("ffmpeg -y -i test.amr -ar 16000 test.wav -v quiet &> /dev/null", "r");
while (fgets (buffer, sizeof(buffer), stream))
{
}
pclose (stream);
The problem with Test 2 is that pclose() is not waiting for the pipe to finish processing. I don't want to have a bunch of FFMPEG output every time I have to do a pipe.
You should only use popen() when you want to send data to, or read data from, the child process (and that is an exclusive-or; if you want to do both, you have to set up the connection yourself).
If you don't want to do that, don't use popen().
As jim mcnamara accurately explained, given that you redirect the output of the child to /dev/null after the pipe is created, the redirection closes the pipe input to your program, so popen() gets zero bytes to read, which counts as EOF. And it returns - there is nothing more for it to read (if there might be more for it, it would not have received EOF).
In this context, use system(); it will wait for the child to finish - even when the output of the child is redirected to /dev/null. In other contexts, it might be appropriate to use the lower-level fork() and exec*() routines instead.
output to /dev/null means that popen (which is calling read() ) does not block on a closed file descriptor for stdout. It returns right away.
You effectively closed stdout by redirecting it (dup() ), in reality it returns EOF

read not blocking on named pipe

i have the following bit of C code which reads from a pipe and then should block but it never blocks
int pipe_fd;
int res;
int open_mode = O_RDONLY;
char buf[100];
int bytes_read = 0;
memset (buf, '\0', sizeof(buf));
pipe_fd = open(FIFO_NAME, open_mode);
if (access(FIFO_NAME, F_OK) == -1)
{
res = mkfifo(FIFO_NAME, 0777);
if (res != 0)
{
fprintf (stderr, "Could not create fifo %s\n", FIFO_NAME);
exit (EXIT_FAILURE);
}
}
for(;;)
{
do
{
res = read(pipe_fd, buf, sizeof(buf));
bytes_read += res;
}while (res > 0);
// process data then go back and block
............
}
It is sent a simple buffer by some code in a bash script like this './test 1'
#!/bin/bash
pipe=/tmp/pipe
if [[ ! -p $pipe ]]; then
echo "Reader not running"
exit 1
fi
if [[ "$1" ]]; then
echo "some string" >$pipe
else
echo "q" >$pipe
fi
I run the C code program in gdb and initially it does block on the read but as soon as i call the bash script the C code no longer blocks , it does successfully read the data from
the buffer and then each time it reads there are 0 bytes read so not sure why its no longer blocking. The 'some string' data is correctly received at the other side.
I just need it to sit there waiting for data process it and then go back and wait for more
I run the C code program in gdb and initially it does block on the read but as soon as i call the bash script the C code no longer blocks , it does successfully read the data from the buffer and then each time it reads there are 0 bytes read so not sure why its no longer blocking. The 'some string' data is correctly received at the other side.
0 means EOF. FIFO can be read or written only when there are processes connected to it for both reading and writing. When there are no more writers (your shell scripts terminated) readers are notified about that through read() returning the EOF.
FIFOs behave that way to be compatible with shell pipe logic e.g.:
$ mkfifo ./tmp1
$ cat < input > ./tmp1 &
$ cat < ./tmp1 > /dev/null
If read() will not return EOF, the second cat would block forever.
I just need it to sit there waiting for data process it and then go back and wait for more
In your C program you have to reopen() the FIFO after read() returned the EOF first time.
P.S. Found quite nice FIFO summary for your. Check the table on the second page.
your bash script closes the pipe so the C is getting an "eof" condition
I think write side shell script close the pipe every time when echo something.
So, the write script need to open the pipe and repeatedly use the opended descriptor to write something and close the opended descripter finally.

Linux C: "Interactive session" with separate read and write named pipes?

I am trying to work with "Introduction to Interprocess Communication Using Named Pipes - Full-Duplex Communication Using Named Pipes", link ; in particular fd_server.c (included below for reference)
Here is my info and compile line:
:~$ cat /etc/issue
Ubuntu 10.04 LTS \n \l
:~$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
:~$ gcc fd_server.c -o fd_server
fd_server.c creates two named pipes, one for reading and one for writing. What one can do, is: in one terminal, run the server and read (through cat) its write pipe:
:~$ ./fd_server & 2>/dev/null
[1] 11354
:~$ cat /tmp/np2
and in another, write (using echo) to server's read pipe:
:~$ echo "heeellloooo" > /tmp/np1
going back to first terminal, one can see:
:~$ cat /tmp/np2
HEEELLLOOOO
0[1]+ Exit 13 ./fd_server 2> /dev/null
What I would like to do, is make sort of a "interactive" (or "shell"-like) session; that is, the server is run as usual, but instead of running cat and echo, I'd like to use something akin to screen. What I mean by that, is that screen can be called like screen /dev/ttyS0 38400, and then it makes a sort of a interactive session, where what is typed in terminal is passed to /dev/ttyS0, and its response is written to terminal. Now, of course, I cannot use screen, because in my case the program has two separate nodes, and as far as I can tell, screen can refer to only one.
How would one go about to achieve this sort of "interactive" session in this context (with two separate read/write pipes)?
Code below:
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <fullduplex.h> /* For name of the named-pipe */
#define NP1 "/tmp/np1"
#define NP2 "/tmp/np2"
#define MAX_BUF_SIZE 255
#include <stdlib.h> //exit
#include <string.h> //strlen
int main(int argc, char *argv[])
{
int rdfd, wrfd, ret_val, count, numread;
char buf[MAX_BUF_SIZE];
/* Create the first named - pipe */
ret_val = mkfifo(NP1, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
exit (1);
}
ret_val = mkfifo(NP2, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
exit (1);
}
/* Open the first named pipe for reading */
rdfd = open(NP1, O_RDONLY);
/* Open the second named pipe for writing */
wrfd = open(NP2, O_WRONLY);
/* Read from the first pipe */
numread = read(rdfd, buf, MAX_BUF_SIZE);
buf[numread] = '0';
fprintf(stderr, "Full Duplex Server : Read From the pipe : %sn", buf);
/* Convert to the string to upper case */
count = 0;
while (count < numread) {
buf[count] = toupper(buf[count]);
count++;
}
/*
* Write the converted string back to the second
* pipe
*/
write(wrfd, buf, strlen(buf));
}
Edit:
Right, just to clarify - it seems I found a document discussing something very similar, it is - a modification of the script there ("For example, the following script configures the device and starts a background process for copying all received data from the serial device to standard output...") for the above program is below:
# stty raw #
( ./fd_server 2>/dev/null; )&
bgPidS=$!
( cat < /tmp/np2 ; )&
bgPid=$!
# Read commands from user, send them to device
echo $(kill -0 $bgPidS 2>/dev/null ; echo $?)
while [ "$(kill -0 $bgPidS 2>/dev/null ; echo $?)" -eq "0" ] && read cmd; do
# redirect debug msgs to stderr, as here we're redirected to /tmp/np1
echo "$? - $bgPidS - $bgPid" >&2
echo "$cmd"
echo -e "\nproc: $(kill -0 $bgPidS 2>/dev/null ; echo $?)" >&2
done >/tmp/np1
echo OUT
# Terminate background read process - if they still exist
if [ "$(kill -0 $bgPid 2>/dev/null ; echo $?)" -eq "0" ] ;
then
kill $bgPid
fi
if [ "$(kill -0 $bgPidS 2>/dev/null ; echo $?)" -eq "0" ] ;
then
kill $bgPidS
fi
# stty cooked
So, saving the script as say starter.sh and calling it, results with the following session:
$ ./starter.sh
0
i'm typing here and pressing [enter] at end
0 - 13496 - 13497
I'M TYPING HERE AND PRESSING [ENTER] AT END
0~�.N=�(�~� �����}����#������~� [garble]
proc: 0
OUT
which is what I'd call for "interactive session" (ignoring the debug statements) - server waits for me to enter a command; it gives its output after it receives a command (and as in this case it exits after first command, so does the starter script as well). Except that, I'd like to not have buffered input, but sent character by character (meaning the above session should exit after first key press, and print out a single letter only - which is what I expected stty raw would help with, but it doesn't: it just kills reaction to both Enter and Ctrl-C :) )
I was just wandering if there already is an existing command (akin to screen in respect to serial devices, I guess) that would accept two such named pipes as arguments, and establish a "terminal" or "shell" like session through them; or would I have to use scripts as above and/or program own 'client' that will behave as a terminal..
If you just want to be able to receive multiple lines, rather than exiting after one, this is simple. You just need to place a loop around your read/write code, like so (quick and dirty):
while( 1 ) {
numread = read(rdfd, buf, MAX_BUF_SIZE);
fprintf(stderr, "Full Duplex Server : Read From the pipe : %sn", buf);
/* Convert to the string to upper case */
count = 0;
while (count < numread) {
buf[count] = toupper(buf[count]);
count++;
}
/*
* Write the converted string back to the second
* pipe
*/
write(wrfd, buf, strlen(buf));
}
Of course, now you have an application which will never exit, and will start doing nothing as soon as it gets an EOF, etc. So, you can reorganize it to check for errors:
numread = read(rdfd, buf, MAX_BUF_SIZE);
while( numread > 0) {
/* ... etc ... */
numread = read(rdfd,buf, MAX_BUF_SIZE);
}
if( numread == 0 ) {
/* ... handle eof ... */
}
if( numread < 0 ) {
/* ... handle io error ... */
}
From the man page, read returns 0 for EOF and -1 for an error (you have read the man page, right? http://linux.die.net/man/2/read ). So what this does is keeps on grabbing bytes from the read pipe until it reaches EOF or some error, in which case you (probably) print a message and exit. That said, you might just do a reopen when you get an EOF so you can get more input.
Once you've modified your program to read continuously, entering multiple lines interactively is simple. Just execute:
cat - > /tmp/np1
The '-' explicitly tells cat to read from stdin (this is the default, so you don't actually need the dash). So cat will pass everything you enter on to your pipe program. You can insert an EOF using Ctrl+D, which will cause cat to stop reading stdin. What happens to your pipe program depends on how you handle the EOF in your read loop.
Now, if you want another program that does all the io, without cat, (so you end up with a stdio echo program), the pseudocode is going to look sort of like this:
const int stdin_fd = 0; // known unix constant!
int readpipe_fd = open the read pipe, as before
int writepipe_fd = open the write pipe, as before
read stdin into buffer
while( stdin is reading correctly ) {
write data from stdin to read pipe
check write is successful
read write pipe into buffer
check read is successful
write buffer to stdout (fprintf is fine)
read stdin into buffer.
}
You can use the read system call to read stdin if you feel like it, but you can also just use stdio. Reading, writing, and opening your pipes should all be identical to your server program, except read/write is all reversed.

Resources