broken pipe between cat and grep on Raspberry Pi - c

I am trying to read the wireless connection link quality in a C program.
I do:
for(;;){
rf_line = popen("cat /proc/net/wireless | grep wlan0", "r");
fgets(line, 80, rf_line);
pclose(rf_line);
...
//more code
}
On the Raspberry Pi with the Wheezy 08/12 image, it crashes with the errno 32, broken pipe.
If I call cat /proc/net/wireless | grep wlan0 from the console, it works fine.
Also if I am trying to debug with gdb, the error does not occur.
On my Laptop with Linux Mint 14 it does never occur.
I tried to prevent this by making a system(...) call. Even with opening a new bash with bash -c ....
I also tried, not to write to the stdout and into a file, without luck.
edit:
with
rf_line = popen("/bin/grep wlan0 /proc/net/wireless", "r");
Increasing the size of the line to 200 had no effect.
I have the same result, errno 32.
edit:
with
rf_line = fopen("/proc/net/wireless","r");
I have the same result, errno 32.
This however leads to the suggestion, that popen does not work correctly, because it is the only pipe left.
Fopen / popen is called very frequently, could this be the issue?
Has anybody a clou, what I could do next?
regards,
Ck

From man 2 write:
EPIPE: fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also receive a SIGPIPE signal. (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.)
So the command, that you executed with popen("...") (not your program) will get the EPIPE error on it's write() and the SIGPIPE signal if you close your end of the pipe before it finishes to write anything.
You need to read every line of the command output, not just first one. Until you'll get EOF.

I'm not really sure how popen works but try. Perhaps it just doesn't work with pipes.
rf_line = popen("grep wlan0 /proc/net/wireless", "r");
Another is to add absolute path like:
rf_line = popen("/bin/grep wlan0 /proc/net/wireless", "r");
Or
rf_line = popen("/usr/bin/grep wlan0 /proc/net/wireless", "r");
UPDATE
This one worked for me.
#include <stdio.h>
int main(int argc, char** argv)
{
char line[200];
line[0] = '\0';
FILE* rf_line = popen("grep wlan0 /proc/net/wireless", "r");
fgets(line, 200, rf_line);
printf("%s", line); /* You can remove this */
pclose(rf_line);
}

Related

fopen() cannot return a variable [duplicate]

I use mkfifo to create a named pipe.
Then I use the following program to open it. However, the program hangs at the line "fopen". Is there something wrong here?
int main(int argc, char** argv) {
char* line = "hello, world!";
FILE* fp = fopen("/tmp/myFIFO", "rw");
fprintf(fp, line);
fclose(fp);
return 0;
}
Try passing "w" as the mode to fopen. "rw" is not a valid mode argument for fopen, and even if it was, you probably don't want to both read and write to the FIFO in the same process (although it is possible, see below).
As an aside, the correct mode argument for opening a file for both reading and writing is either "r+" or "w+" (see the answers to this question for the differences).
This program will correctly write to the FIFO:
#include <stdio.h>
int main(int argc, char** argv) {
FILE* fp = fopen("/tmp/myFIFO", "w");
fprintf(fp, "Hello, world!\n");
fclose(fp);
return 0;
}
Note that fopen in the above program will block until the FIFO is opened for reading. When it blocks, run this in another terminal:
$ cat /tmp/myFIFO
Hello, world!
$
The reason why it blocks is because fopen does not pass O_NONBLOCK to open:
$ strace -P /tmp/myFIFO ./a.out
open("/tmp/myFIFO", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...
Some background on how FIFOs are opened
Read-only, without O_NONBLOCK: open blocks until another process opens the FIFO for writing. This is the behavior when using fopen with mode argument "r".
Write-only, without O_NONBLOCK: open blocks until another process opens the FIFO for reading. This is the behavior when using fopen with mode argument "w".
Read-only, with O_NONBLOCK: open returns immediately.
Write-only, with O_NONBLOCK: open returns an error with errno set to ENXIO unless another process has the FIFO open for reading.
Info from "Advanced Programming in the UNIX Environment" by W. Richard Stevens.
Opening a FIFO for read and write
Opening a FIFO for reading and writing within the same process is also possible with Linux. The Linux FIFO man page states:
Under Linux, opening a FIFO for read and write will succeed both in
blocking and nonblocking mode. POSIX leaves this behavior undefined.
This can be used to open a FIFO for writing while there are no readers
available. A process that uses both ends of the connection in order
to communicate with itself should be very careful to avoid deadlocks.
Here's a program which writes to and reads from the same FIFO:
#include <stdio.h>
int main(int argc, const char *argv[]) {
char buf[100] = {0};
FILE* fp = fopen("/tmp/myFIFO", "r+");
fprintf(fp, "Hello, world!\n");
fgets(buf, sizeof(buf), fp);
printf("%s", buf);
fclose(fp);
return 0;
}
It does not block, and returns immediately:
$ gcc fifo.c && ./a.out
Hello, world!
Note that this is not portable and may not work on operating systems besides Linux.
The process blocks until the other end of the pipe gets opened.

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) {
:

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)

Named pipe results in infinite loop/no output [duplicate]

I use mkfifo to create a named pipe.
Then I use the following program to open it. However, the program hangs at the line "fopen". Is there something wrong here?
int main(int argc, char** argv) {
char* line = "hello, world!";
FILE* fp = fopen("/tmp/myFIFO", "rw");
fprintf(fp, line);
fclose(fp);
return 0;
}
Try passing "w" as the mode to fopen. "rw" is not a valid mode argument for fopen, and even if it was, you probably don't want to both read and write to the FIFO in the same process (although it is possible, see below).
As an aside, the correct mode argument for opening a file for both reading and writing is either "r+" or "w+" (see the answers to this question for the differences).
This program will correctly write to the FIFO:
#include <stdio.h>
int main(int argc, char** argv) {
FILE* fp = fopen("/tmp/myFIFO", "w");
fprintf(fp, "Hello, world!\n");
fclose(fp);
return 0;
}
Note that fopen in the above program will block until the FIFO is opened for reading. When it blocks, run this in another terminal:
$ cat /tmp/myFIFO
Hello, world!
$
The reason why it blocks is because fopen does not pass O_NONBLOCK to open:
$ strace -P /tmp/myFIFO ./a.out
open("/tmp/myFIFO", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...
Some background on how FIFOs are opened
Read-only, without O_NONBLOCK: open blocks until another process opens the FIFO for writing. This is the behavior when using fopen with mode argument "r".
Write-only, without O_NONBLOCK: open blocks until another process opens the FIFO for reading. This is the behavior when using fopen with mode argument "w".
Read-only, with O_NONBLOCK: open returns immediately.
Write-only, with O_NONBLOCK: open returns an error with errno set to ENXIO unless another process has the FIFO open for reading.
Info from "Advanced Programming in the UNIX Environment" by W. Richard Stevens.
Opening a FIFO for read and write
Opening a FIFO for reading and writing within the same process is also possible with Linux. The Linux FIFO man page states:
Under Linux, opening a FIFO for read and write will succeed both in
blocking and nonblocking mode. POSIX leaves this behavior undefined.
This can be used to open a FIFO for writing while there are no readers
available. A process that uses both ends of the connection in order
to communicate with itself should be very careful to avoid deadlocks.
Here's a program which writes to and reads from the same FIFO:
#include <stdio.h>
int main(int argc, const char *argv[]) {
char buf[100] = {0};
FILE* fp = fopen("/tmp/myFIFO", "r+");
fprintf(fp, "Hello, world!\n");
fgets(buf, sizeof(buf), fp);
printf("%s", buf);
fclose(fp);
return 0;
}
It does not block, and returns immediately:
$ gcc fifo.c && ./a.out
Hello, world!
Note that this is not portable and may not work on operating systems besides Linux.
The process blocks until the other end of the pipe gets opened.

How to execute a bash command in C and retrieve output?

I'm trying to execute a bash command from c and retrieve and show the result.
I've tried with system but it doesn't work.
My code looks like:
char command[200];
sprintf(command,"lsof -iTCP:%d | cut -d\"\" -f1 | tail -1",port);
printf("Port %d is open\n and is listened by %s",port,system(command));
Please help. I need this .
Edit aside from the actual question, I'd be using
sudo netstat -tlpn
(shows the processes that are listening on TCP ports, not resolving the ports/addresses)
Perhaps combine it with a bit of grep:
sudo netstat -tlpn | grep :7761
to find where port :7761 is being listened?
You can use popen.
With popen you get the benefit that you receive the process output asynchronously (you will be able to stop processing if the answer is on the first line of output without having to wait for the subprocess to complete; simply pclose and the subprocess will die with SIGPIPE)
A sample straight from the Standards Documentation:
The following example demonstrates the use of popen() and pclose() to execute the command ls * in order to obtain a list of files in the current directory:
#include <stdio.h>
...
FILE *fp;
int status;
char path[PATH_MAX];
fp = popen("ls *", "r");
if (fp == NULL)
/* Handle error */;
while (fgets(path, PATH_MAX, fp) != NULL)
printf("%s", path);
status = pclose(fp);
if (status == -1) {
/* Error reported by pclose() */
...
} else {
/* Use macros described under wait() to inspect `status' in order
to determine success/failure of command executed by popen() */
...
}
system(command) returns the return code of the command, not its output.
If you want to read the output of a command, you should use popen
This returns a file descriptor to the output, which you can read from just like a normal file.

Resources