Buffering while popen working - c

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)

Related

Terminate cat command immediately after using in 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) {
:

Use opened file descriptor

I've got 2 programs, and in one i'm opening a file to read and from the other one i'm trying to read from file :
first program
fd = open("test.txt",O_RDONLY);
printf("%d\n",fd);
while(1);
second program :
char sir[100];
int fd, result;
scanf("%d",&fd);
rez = read(fd,((void*)sir), 2);
In the second program i read what i printed in first program. Why this code doesn't work and how can i read from that file descriptor from program nr 2?
File descriptors are unique to the process. Also you need to write to the file descriptor.
There are several problems:
fd = open("test.txt", O_RDONLY) opens the file for reading. If I understand what you are trying to do, you want to create the file and open it for writing. That would be fd = open("test.txt", O_CREAT | O_WRONLY).
printf("%d\n",fd) displays the value of the file handle. While that might be useful for debugging, I think you want something which writes to the file handle. write (fd, "hello", 5) is closer to that.
while(1); is an infinite CPU busy loop. This is not very useful.
Similarly the second program has issues:
fd = scanf("%d",&fd) is peculiar. I think you want to open the file just written, no? Instead, fd = open("test.txt", O_RDONLY).
With that corrected, the program can then read the content into the variable read (fd, sir, sizeof sir).
See if those help you.
If you are not primarily working with binary data in the files, the fopen() and fprintf() library calls are more convenient.

reading from a file descriptor in C

(correct me if im wrong on my terms) So i need to read from a file descriptor, but the read method takes in a int for byte size to read that much OR i can use O_NONBLOCK, but i still have to setup up a buffer size of an unknown size. making it difficult. heres what i have so far
this is my method that handles all the polling and mkfifo. and N is already predefined in main
struct pollfd pfd[N];
int i;
for(i = 0; i < N; i++)
{
char fileName[32];
snprintf (fileName, sizeof(fileName), "%d_%di", pid, i);
mkfifo(fileName, 0666);
pfd[i].fd = open(fileName, O_RDONLY | O_NDELAY);
pfd[i].events = POLLIN;
pfd[i].revents = 0;
snprintf (fileName, sizeof(fileName), "%d_%do", pid, i);
mkfifo(fileName, 0666);
i++;
pfd[i].fd = open(fileName, O_WRONLY | O_NDELAY);
pfd[i].events = POLLOUT;
pfd[i].revents = 0;
i--;
}
while(1)
{
int len, n;
n = poll(pfd, N, 2000);
if( n < 0 )
{
printf("ERROR on poll");
continue;
}
if(n == 0)
{
printf("waiting....\n");
continue;
}
for(i = 0; i < N; i++)
{
char buff[1024]; <---i dont want to do this
if (pfd[i].revents & POLLIN)
{
printf("Processing input....\n");
read(pfd[i].fd, buff, O_NONBLOCK);
readBattlefield(buff);
print_battleField_stats();
pfd[i].fd = 0;
}
}
}
i also read somewhere that once read() reads all the data coming, it empties the pipe, meaning i can use the same again for another incoming data. but it doesnt empty the pipe because i cant use the same pipe again. I asked my professor but all he says was to use something like scanf, but how do use scanf if scanf takes a FILE stream, and the poll.fd is an int? essentially my ultimate question is, how to read the incoming data through the file descriptor using scan or of other sort? using scan will help me more with handling the data.
EDIT:
in another terminal i have to put cat file > (named_file)
and my main program will read the input data. heres what the input data looks like
3 3
1 2 0
0 2 0
3 0 0
first 2 numbers are grid information and player number, and after that is grid, but this a simplified version, ill be dealing with sizes over 100's of players and grids of over 1000's
char buff[1024]; <---i dont want to do this
What would you like to do then? This is how it works. This is not how it works:
read(pfd[i].fd, buff, O_NONBLOCK);
This will compile because O_NONBLOCK is an integer #define, but it is absolutely and unequivocally incorrect. The third argument to read() is a number of bytes to read. Not a flag. Period. It may be zero, but what you've done here is pass an arbitrary number -- whatever the value of O_NONBLOCK is, which could easily be more than 1024, the size of your buffer. This does not set the read non-block. recv() is similar to read() and does take such flags as a forth argument, but you can't use that with a file descriptor. If you want to set non-block on a file descriptor, you must do it with open() or fcntl().
how to read the incoming data through the file descriptor using scan or of other sort?
You can create a FILE* stream from an open descriptor with fdopen().
i also read somewhere that once read() reads all the data coming, it empties the pipe, meaning i can use the same again for another incoming data. but it doesnt empty the pipe because i cant use the same pipe again.
Once you reach EOF (because the writer closed the connection), read() will return 0, and continue to return 0 immediately until someone opens the pipe again.
If you set the descriptor non-block, read() will always return immediately; if there is someone connected and nothing to read, it will return -1 but errno will == EAGAIN. See man 2 read.
man fifo is definitely something you should read; if there's anything you aren't sure about, ask a specific question based on that.
And don't forget: Fix that read() call. It's wrong. W R O N G. Your prof/TA/whoever will not miss that.

Infinite read(2) with piped command

I'd like to have some precision about read(2) behaviour on Linux systems,
I'm trying to make a shell and I got a problem while reading the input.
I do something like
read(0, BUF, 4096);
So the thing is on bash (and most shell) you can pipe a command like this :
echo ls | bash
Bash will execute ls only once but when I do this read always return me the same buffer, "ls"
so it goes in infinite loop.
I wanted to know why read(2) doesn't return me 0 thanks you.
You need to examine read's return value. If it returns 0, then it reached the end of the input stream. That is, instead of this:
read(0, BUF, 4096);
you need to write:
int bytes_read = read(0, BUF, 4096);
and then check if bytes_read is zero.
You're probably not clearing the buffer after each read. If there's nothing to read, read() will return 0 and write nothing to the buffer. If the buffer's not cleared, whatever was in it before hand will still be there, which is why you keep getting your infinite ls - there's still only the original ls in there, but you keep treating it as new input.

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.

Resources