I have the code below that I refer the thread on here to use the popen function
int main(int argc,char *argv[]){
FILE* file = popen("ntpdate", "r");
char buffer[100];
fscanf(file, "%100s", buffer);
pclose(file);
printf("buffer is :%s\n", buffer);
return 0;
}
It outputs:
21 Apr 03:03:03 ntpdate[4393]: no server can be used, exiting
buffer is:
why printf does not output anything? If I use ls as a command, then printf outputs the ls output. what am I doing wrong ntpdate executing?
If I execute the code below (referring the webpage)
#define COMMAND_LEN 8
#define DATA_SIZE 512
int main(int argc,char *argv[]){
FILE *pf;
char command[COMMAND_LEN];
char data[DATA_SIZE];
// Execute a process listing
sprintf(command, "ntpdate");
// Setup our pipe for reading and execute our command.
pf = popen(command,"r");
if(!pf){
fprintf(stderr, "Could not open pipe for output.\n");
return;
}
// Grab data from process execution
fgets(data, DATA_SIZE , pf);
// Print grabbed data to the screen.
fprintf(stdout, "-%s-\n",data);
if (pclose(pf) != 0)
fprintf(stderr," Error: Failed to close command stream \n");
return 0;
}
I get
21 Apr 03:15:45 ntpdate[5334]: no servers can be used, exiting
-�2}�����"|�4#|�-
Error: Failed to close command stream
what are wrongs on the codes above?
Since the output is going to stderr you need to redirect stderr like so:
FILE* file = popen("ntpdate 2>&1", "r");
this will redirect stderr to stdout and so you will see output from both. Second issue fscanf will stop at the first space so you can replace with fgets:
fgets(buffer, 100, file);
As Shafik Yaghmour correctly diagnosed, the output you see from ntpdate is written (correctly) to its standard error, which is the same as your programs standard error.
To get the error messages sent down the pipe, use:
FILE *file = popen("ntpdate 2>&1", "r");
That sends the standard error output from ntpdate to the standard output of the command, which is the pipe you're reading from.
Of course, it looks like using ntpdate isn't going to work well until you've configured something.
Related
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.
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.
Why does fprintf give different results in the following example programs?
Example 1:
int main(){
FILE *f;
char buf[512];
char name[128] = {"filename"};
f = fopen(name, "w");
fprintf(f, "asdas\n");
fprintf(f, "asdas\n");
while(1){}
return 0;
}
If I terminate this program using CTRL+C, I get an empty file named filename.
However, using
Example 2:
int main(){
FILE *f;
char buf[512];
char name[128] = {"wpa_supplicant.conf"};
f = fopen(name,"w");
while(1){
fprintf(f, "asdas\n");
}
return 0;
}
If I terminate this program using CTRL+C, I get file named filename, and it contains many lines with the string asdas.
Why are the strings not written to the file in the first example, but they are written to the file in the second example?
In the second case, there are enough fprintf calls for the internal buffers to be flushed to disk.
With the first program, if you put a fflush(f) before the while loop, the strings will be written to the file.
#include <stdio.h>
int main(void) {
FILE *f = fopen("filename", "w");
if (!f) {
perror("Failed to open 'filename' for writing");
exit(EXIT_FAILURE);
}
fprintf(f, "asdas\n");
fprintf(f, "asdas\n");
if ( fflush(f) != 0 ) {
perror("Flushing output failed");
exit(EXIT_FAILURE);
}
while(1){}
return 0;
}
Output:
C:\...\Temp> cl file.c
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x64
...
/out:file.exe
C:\...\Temp> file
^C
C:\...\Temp> type filename
asdas
asdas
Keep in mind:
Upon successful completion, fflush() shall return 0; otherwise, it shall set the error indicator for the stream, return EOF, and set errno to indicate the error.
As mentioned in the answer by #SinanÜnür this is indeed an issue with the buffering of data in internal buffers. You need to flush manually in the first case to get that data actually written into the file.
However, FWIW, I just want to add here, you see this behavior because of the abnormal termination of the program by a signal (generated by CTRL+C).
If your program would have ended normally, (for example, by calling exit(), after a large-enough but controlled while() loop), then both the cases would have shown the same behavior, as in that scenario, all the open streams would have been flushed automatically.
The exit() function shall then flush all open streams with unwritten buffered data and close all open streams. Finally, the process shall be terminated ...
Basically what I want to do is have a program with int main(argc, *argv[]) and instead of writing chars into command line, I want to have my program read those words from a file. How could I accomplish this? Is there a special command in Linux for that?
You can use standard redirect operations in a *nix shell to pass files as input:
./myprogram < inputfile.txt
This statement executes your program (myprogram) and pumps the data inside of inputfile.txt to your program
You can also redirect the output of program to a file in a similar fashion:
./myprogram > outputfile.txt
Instead of doing
for(int i = 1; i < argc; i++)
{
insert(&trie, argv[i]);
}
you could doing something like
FILE *input;
char *line;
....
while (fscanf(input, "%ms", &line) != EOF) {
insert(&trie, line);
/* If you make a copy of line in `insert()`, you should
* free `line` at here; if you do not, free it later. */
free(line);
}
Use redirection
yourprogram < youtextfile
will offer the content of yourtextfile as standard input (stdin) to yourprogram. Likewise
yourprogram > yourothertextfile
will send everything the program writes to standard output (stdout) to yourothertextfile
You'll notice when reading man pages that most system calls have a version that works directly with stdin or stdout
For example consider the printf family:
printf ("hello world\n");
is a shorter version of
fprintf (stdout,"hello world\n");
and the same goes for scanf and stdin.
This is only the most basic usage of redirection, which in my opinion is one of the key aspects of "the unix way of doing things". As such, you'll find lots of articles and tutorials that show examples that are a lot more advanced than what I wrote here. Have a look at this Linux Documentation Project page on redirection to get started.
EDIT: getting fed input via redirection ior interactively "looks" the same to the program, so it will react the same to redirected input as it does to console input. This means that if your program expects data line-wise (eg because it uses gets() to read lines), the input text file should be organized in lines.
By default, every program you execute on POSIX-compliant systems has three file descriptors open (see <unistd.h> for the macros' definition): the standard input (STDOUT_FILENO), the standard output (STDOUT_FILENO), and the error output (STDERR_FILENO), which is tied to the console.
Since you said you want read lines, I believe the ssize_t getline(char **lineptr, size_t *n, FILE *stream) function can do the job. It takes a stream (FILE pointer) as a third argument, so you must either use fopen(3) to open a file, or a combination of open(2) and fdopen(3).
Getting inspiration from man 3 getline, here is a program demonstrating what you want:
#define _GNU_SOURCE
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp;
size_t len;
char *line;
ssize_t bytes_read;
len = 0;
line = NULL;
if (argc > 1)
{
fp = fopen(argv[1], "r");
if (fp == NULL)
{
perror(*argv);
exit(EXIT_FAILURE);
}
}
else
fp = stdin;
while ((bytes_read = getline(&line, &len, fp)) != -1)
printf("[%2zi] %s", bytes_read, line);
free(line);
exit(EXIT_SUCCESS);
}
Without arguments, this program reads lines from the standard input: you can either feed it lines like echo "This is a line of 31 characters" | ./a.out or execute it directly and write your input from there (finish with ^D).
With a file as an argument, it will output every line from the file, and then exit.
You can have your executable read its arguments on the command line and use xargs, the special Linux command for passing the contents of a file to a command as arguments.
An alternative to xargs is parallel.
I'm trying to execute other programs within my C program. My first attempt was with popen. When I try to read from pipe I only get a reply of 1 byte and nothing in buf. I'm not sure as to the reasoning behind this.
popen example:
#include<stdio.h>
#include<unistd.h>
int main(int argc, char* argv[])
{
FILE* pipe;
if ((pipe=(FILE*)popen("./test.php","r"))==NULL)
printf("this is not working\n");
char buf[1024] = {'\0'};
int fd=fileno(pipe);
int bytes = read(fd, buf, 1024);
printf("bytes read %d\n", bytes);
printf("The program: %s\n", buf);
if(pclose(pipe)<0)
printf("not working\n");
return 0;
}
php example
#!/usr/bin/php
<?php
echo "THIS IS A TEST THAT WORKED\n";
?>
The output:
bytes read 1
The program:
The output of ls:
ls -l test.php
-rwxr-xr-x+ 1 tpar44 user 62 Nov 10 14:42 test.php
Any help in this would be greatly appreciated!
Thanks!
You need to execute the php interpreter and pass the name of the script as argument, when using popen if your script does not have the shebang because the shell won't know which interpreter to use:
fp = popen("php /path/to/script/test.php", "r");
If the script has the shebang line you can just execute it, because popen uses the shell to execute commands and it can find out which one to use, so you could just do this:
fp = popen("/path/to/script/test.php", "r");
However, make sure the script is executable:
chmod +x test.php
you could also use execl() but you have to specify the path to the binary because execl doesn't use the shell:
execl("/usr/bin/php", "/usr/bin/php", "-q",
"/path/to/script/test.php", (char *) NULL);
Don't forget to actually read from the pipe ;)
fread(buf, 1, 1024, pipe);