How to read stdout (with \r) of process opened with popen - c

I need to read output of a program that uses carriage returns (\r) to make its output.
I have an old utility with output like this:
#include <stdio.h>
#include <unistd.h>
int main() {
setvbuf(stdout, (char*)NULL,_IONBF, 0);
fprintf(stdout, "Start\n");
for (auto i = 0; i < 100; ++i) {
fprintf(stdout, "\r%2d", i);
usleep(100000);
}
fprintf(stdout, "\nEnd\n");
return 0;
}
So I execute it with popen from my program and I need to trace a progress:
#include <memory>
#include <stdio.h>
int main(int argc, char* argv[]) {
if (argc != 2) {
return -1;
}
std::unique_ptr<FILE, int(*)(FILE*)> filePtr( popen(argv[1], "r"), &pclose );
int c = fgetc(filePtr.get());
while (c != EOF); {
printf("%c", c);
c = fgetc(filePtr.get());
}
return 0;
}
This work fine only without \r in stdout. Does anybody know is it possible to execute a process and read all output even with carriaage return symbols?

The problem here is that the carriage-return '\r' isn't really anything special, it's how you handle it that makes it different.
A terminal program uses it to control cursor position, but that's only done inside the terminal program itself, it's not "built-in" in the '\r' character.
If you want to handle it in a special way then you need to create your program that way.

Related

What is the importance of adding "\n" to stdout when it's redirected to another process?

So, I'm playing with pipes in c, and I have an exercise where I call a program through command line as this: "./self 1" which then calls itself with execlp but with an argument 2: "./self 2" which further on calls itself with argument 3: "./self 3". The point of these processes is this: process1 takes a line from keyboard and puts it in pipe1, then process2 gets the line from pipe1 and puts it in pipe2, then process3 gets it from pipe2 and counts the number of space characters. This code never works if I dont print a newline character on the screen before taking inputs with fprintf(stdout,"\n"); . Why is that?
Here is the code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
if (strcmp(argv[1], "1") == 0) {
int fdpipe1[2];
if (pipe(fdpipe1)) {
printf("Error pipe1\n");
return 0;
}
pid_t p;
p = fork();
if (p == 0) {
close(fdpipe1[1]);
dup2(fdpipe1[0], 0);
execlp("./self", "./self", "2", NULL);
} else {
close(fdpipe1[0]);
fprintf(stdout, "\n");
dup2(fdpipe1[1], 1);
char input[100];
gets(input);
puts(input);
wait(NULL);
}
}
else if (strcmp(argv[1], "2") == 0) {
int fdpipe2[2];
if (pipe(fdpipe2)) {
printf("Error pipe2\n");
return 0;
}
pid_t p;
p = fork();
if (p == 0) {
close(fdpipe2[1]);
dup2(fdpipe2[0], 0);
execlp("./self", "./self", "3", NULL);
} else {
close(fdpipe2[0]);
fprintf(stdout, "\n");
dup2(fdpipe2[1], 1);
char input[100];
gets(input);
puts(input);
wait(NULL);
}
}
else if (strcmp(argv[1], "3") == 0) {
char input[100];
gets(input);
int i = 0, counter = 0;
while (input[i] != '\0') {
if (input[i++] == ' ') counter++;
}
printf("%d\n", counter);
}
return;
}
In this kind of construct, when you connect stdout from a process to stdin of another process via unnamed pipe, a newline character is added usually to ensure the stream is sent, i.e. the stdout buffer is flushed, as a parallel example, when you use scanf, only when you hit enter (a newline is added to stdin) is the stream read, a similar principle applies here.
I would suggest you use STDIN_FILENO and STDOUT_FILENO
built in macros instead of the hard coded file descriptors, if not for anything else, it makes the code more readable for someone who is unfamiliar with the matter.
Please avoid using gets, this is a dangerous function, it does not check the bounds of the destination buffer, it can cause all kinds of trouble, so much so it was deprecated and later removed from the standard, though it still can be used with some compilers, for legacy reasons I would imagine, check this fantastic answer on a post about this topic:
Why is the gets function so dangerous that it should not be used?
The advice is to use fgets instead.

c - Why no race condition with fopen / fprintf [duplicate]

This question already has an answer here:
Flushing buffers in C
(1 answer)
Closed 3 years ago.
I am trying to simulate a race condition (is this a correct term?) in order to fix it with semaphores afterward.
I have a master.c process:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
for(int i = 0; i < 100; ++i)
{
if (fork() == 0)
{
char str[12];
sprintf(str, "%d", i%10);
execl("./slave", "slave", str, (char *)0);
}
}
return 0;
}
And a slave.c process which prints into a file:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE *p_file;
p_file = fopen("out.txt", "a");
for (int i = 0; i < 100; ++i)
{
usleep(100000); // I tried using this but it changes nothing
fprintf(p_file, "%s", argv[1]);
}
fprintf(p_file, "\n");
return 0;
}
The output file out.txt looks like this:
https://pastebin.com/nU6YsRsp
The order is "random", but no data is not corrupted for some reason. Why is that?
Because stdio uses buffered output by default when writing to a file, and everything you're printing in each process fits into a single buffer. The buffer doesn't get flushed until the process exits, and then it's written as a single write() call, which is small enough to be written atomically to the file.
Call fflush(p_file); after each fprintf() and you'll get more mixed up results. Or call setvbuf() to disable buffering.

popen not working as expected

I have a program where I need to communicate with another program on its standard input and output. I can use a pipe to send it input and redirect its output to a specified file to be read when it is done, and that works fine. I am not using pipe and dup2 because I would like my program to at least somewhat work on windows as well as linux.
My issue is that I want to use the pipes to stream data.
I tried the following snippet:
#include <stdio.h>
int main()
{
while (!feof(stdin)) {
int x;
scanf("%d", &x);
printf("%x ", x);
fflush(0);
}
return 0;
}
in conjunction with:
#include <unistd.h>
#include <stdio.h>
int main()
{
int x;
FILE *p = popen("./test > tmp.datafile", "w");
FILE *f = fopen("tmp.datafile", "r");
for (int i = 0; i < 100; ++i) {
fprintf(p, "%d", i);
sleep(1);
x = fgetc(f);
printf("%c ", x);
fflush(0);
}
fclose(f);
pclose(p);
return 0;
}
However no matter what I do, I just keep getting nulls out of the file. I suspect that perhaps there are concurrency issues, in that I try to read the file before the test executable finishes flushing it, however I am not sure how to fix this.
Is there a better way to communicate with a program via standard streams in c?
fgetc() won't read past EOF once EOF has been reached — which may happen on the very first read. Doing something like
if(feof(f)) {
clearerr(f);
sleep(1);
} else {
printf("%c ", x);
}
should sort-of solve the issue with a busy loop.
A better idea would be to wait for the file to change once EOF has been reached, but that would require system-specific calls.
Beware of another race condition: fopen may happen before the file has been created by the command started via popen.
while(!(f = fopen(..., "r"))
sleep(1);
It's another busy loop and overall not a good solution that should only be used if dup2() is not available.
One of the issues in your code is that you are not writing any white space to the input of p, because of which the scanf() call in ./test is waiting for the input to finish so that it could read the value. Because of which the stdout of ./test remains empty. Fix it by something like this:
fprintf(p, "%d\n", i);
Also, consider using unbuffered I/O functions inside the ./test program. printf is part of the buffered I/O family of functions and the output might not be written immediately to the file.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
while (!feof(stdin)) {
int x;
char s;
scanf("%d", &x);
sprintf(&s, "%x", x);
write(STDOUT_FILENO, &s, 1);
fflush(stdout);
}
return 0;
}

Stop some commands used in the system() function

I have a problem with system() function.
I need to implement a simple bash, one of the modules of the my project is to permit user types some bash command to execute it.
Above what i'm doing actually:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// similar to gets
int reads(char* str)
{
#ifndef WIN32
fflush(stdout);
strcpy(str,GetServiceLine());
#else
gets(str);
#endif
return 1;
}
int main(void) {
char str[100];
while(strcmp(str, "exit")) {
printf("\nNote: type \"exit\" to return menu\n");
printf("MyBash$ ");
reads(str);
system(str);
}
return 0;
}
My problem is with commands like ping.
When i run this code on my PC and i try execute ping command for a legal IP it works fine, i can stop the ping process using CTRL+C, but when i run it on my target on the same way i can't use CTRL+C and my process keep always at system() call.
Does somebody can help me?
Note: i read this post about how to use CTRL+C to break a system function. I tried the suggestion but didn't work.
Thanks.
Since you hadn't tried it yet I'll throw it up here as a suggestion. You can always install a signal handler to catch signals that you are interested in.
Here's a quick example using (mostly) your code which demonstrates how it's done:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void intHandler(int dummy)
{
exit(1); // Do whatever you want here to handle it...
}
int main(void)
{
char str[100];
signal(SIGINT, intHandler);
signal(SIGKILL, intHandler);
while(strcmp(str, "exit")) {
printf("\nNote: type \"exit\" to return menu\n");
printf("MyBash$ ");
gets(str);
system(str);
}
return 0;
}
I can catch a ctrl+C using this, but I'm not sure if it's what you're looking for.
After the comments above i just thought of explaining why exactly you can't control this in a graceful manner (some hacks are suggested in comments though).
system command is going to behave exactly if you forked a child process and then called exec on the child for executing the binary passed to exec as an argument.
The system() function shall ignore the SIGINT and SIGQUIT signals, and shall block the SIGCHLD signal, while waiting for the command to terminate. If this might cause the application to miss a signal that would have killed it, then the application should examine the return value from system() and take whatever action is appropriate.
Remember, this is very much OS specific behavior and there is no standard as such.
system() function call in Linux
Internally ping utility would run on icmp and waits until a response is received from the other node.
You might write a signal handler as suggested in another answer and call a killpid() but it would be blocked until the call to system() returns. This is stated in the specs of the function. So you might be able to terminate but only AFTER the call has returned. :)
Below the code used to fix my problem. I don't know if is the better solution, but solved my problem in this case.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// similar to gets
int reads(char* str)
{
#ifndef WIN32
fflush(stdout);
strcpy(str,GetServiceLine());
#else
gets(str);
#endif
return 1;
}
void getCommandName(char input[], char output[])
{
int count=0;
while (input[count] != NULL && input[count] != ' ' && input[count] != '\0') {
output[count] = input[count];
count++;
}
}
int killLastCommand(int pid)
{
char commandKill[30];
memset(commandKill, 0, 30);
sprintf(commandKill, "kill -9 %d", pid);
return(!system(commandKill));
}
int main(void) {
FILE *fp; //Will be used with popen()
char str[100];
char lastCommandName[50];
char pidofCommand[50];
char strLastPIDCommand[10];
int lastPIDCommand=0;
memset (str, 0, 100);
while(strcmp(str, "exit")) {
if (lastPIDCommand == 0) {
memset (lastCommandName, 0, 50); //Clean lastCommandName array
memset (pidofCommand, 0, 50); //Clean pidofCommand array
memset (strLastPIDCommand, 0, 10); //Clean strLastPIDCommand array
printf("\n\nNote: type \"exit\" to return menu\n");
printf("MyBash$ ");
reads(str);
if (strcmp(str, "exit")) {
sprintf(str, "%s &", str);
}
getCommandName(str, lastCommandName);
system(str);
sleep(1); //Sleep to guarantee than command will end
sprintf(pidofCommand, "pidof %s", lastCommandName);
//Saving PID
fp = popen(pidofCommand, "r");
if (fp) {
fgets(strLastPIDCommand, 10, fp);
lastPIDCommand = atoi(strLastPIDCommand);
} else {
//Handle error
}
pclose(fp);
printf("commandName = %s\r\n", lastCommandName);
printf("pid = %d\r\n", lastPIDCommand);
} else {
printf("\n\nYou have a command running, press 'kill' to stop it before to type another command\n");
printf("EITVBash$ \n\n");
reads(str);
// if (str[0] == 0x03) { //CTRL+C hexa code
if (!strcmp(str, "kill")) {
if (killLastCommand(lastPIDCommand)) {
lastPIDCommand = 0;
}
}
}
}
return 0;
}
My implementation probably isn't clean, but i don't have much experience with c.
Thanks everybody.

Send input to a program and get control back

I have been stuck on this for some time.
Let's say I have a C program like the following. I want to be able to send this program some string and get the control after that.
If I do:
--> cat myfile | myprogram
or
--> echo "0123" | myprogram
or
--> myprogram < myfile
I get the ouput (myfile contains "0123")
30 31 32 33
Using the -n option raises a segfault
--> echo -n mystring | ./test
zsh: done echo -n "0123" |
zsh: segmentation fault ./test
I also tried with a named pipe, but it didn't work either.
I would like to be able to do something like
cat myfile | myprogram
and get back the control so that I can type other characters.
1 #include <stdlib.h>
2 #include <stdio.h>
3
4 int main (int argc, char *argv[]) {
6 int i = 0, j;
7 unsigned char buf[512];
8 unsigned char x;
9
10 while ((x = getchar()) != '\n') {
11 buf[i] = x;
12 i++;
13 }
14
16 for (j = 0; j < i; j++) {
17 printf("%x ", buf[j]);
18 }
19 printf ( "\n" );
20
21 return EXIT_SUCCESS;
22 } // end of function main
EDIT:
Below is the wrapper I have come up with.
It does everything I want, except that the output of the child exec-ed file is not properly displayed.
Without the wrapper:
$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
2+2
4
With the wrapper:
$ ./wrapper bc
2+2
enter
4
Deleting the line
dup2(pipefd[0], 0); // Set the read end of the pipe as stdin.
makes the child stdout display correctly, but of course breaks the wrapper.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <assert.h>
int main(int argc, char const *argv[]) {
int cpid;
int pipefd[2];
if (pipe(pipefd) == -1) { perror("pipe.\n"); exit(errno); }
cpid = fork();
if (cpid == -1) { perror("fork."); exit(errno); }
if (cpid) {
// Parent --------------------------------------------------------
int buf_size = 8192;
char buf[buf_size];
size_t file;
// Close the unused read end of the pipe.
close(pipefd[0]);
// Leave a bit of time to the child to display its initial input.
sleep(2);
while (1) {
gets(buf);
if (strcmp("enter", buf) == 0) {
write(pipefd[1], "\n", 1);
} else if (-1 != (file = open(buf, O_RDONLY))) {
// Dump the output of the file to the child's stdin.
char c;
while(read(file, &c, 1) != 0) {
switch(c) {
case '\n':
printf("(skipped \\n)");
break;
default:
printf("%c", c);
write(pipefd[1], &c, 1);
};
}
printf("\n");
} else {
// Dump input to the child's stdin, without trailing '\n'.
for (int i = 0; (buf[i] != 0); i++) {
write(pipefd[1], buf + i, 1);
}
}
}
// Wait for the child to exit.
printf("Waiting for child to exit.\n");
wait(NULL);
} else {
// Child ---------------------------------------------------------
// Close the unused write end of the pipe.
close(pipefd[1]);
// Set the read end of the pipe as stdin.
dup2(pipefd[0], 0); // Set the read end of the pipe as stdin.
char** program_arguments = (char**)(argv + 1);
if (execvp(argv[1], program_arguments) < 0) {
perror("execvp.\n");
exit(errno);
}
}
}
I do not think it is possible to achieve this using named pipes if you can not modify the behavior of the program. Since in essence named pipes are no different then giving the output from standard input with redirection.
I also do not think it is possible if you use pipe or redirection properties of the shell, since always an EOF is sent to your program in this case and you can not ignore EOF since you can not modify the program.
A possible solution is to use a wrapper. The wrapper will first read the prepared input, send them to your program, after the prepared input finishes the wrapper switches to standard input. Actual program just keeps consuming input, it is not aware of the actual source of the data.
Only drawback is, you can not provide prepared input with pipes or redirection, you have to supply a filename. (I'm not sure a named pipe will work or not.) The reason is obvious, if you provide the prepared input to wrapper from standard input then the same problem exists for wrapper. By this way you are just delegating the problem to wrapper, which you can design any way you want.
A possible implementation in C (modified from a similar wrapper I've used, not tested extensively):
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
int main(int argc, char * argv[]) {
char c;
char **pargs ;
char buf[20];
int n;
int pipe_fd[2];
int pid;
pargs = argv+2;
if (pipe(pipe_fd) < 0) {
perror("pipe failed");
exit(errno);
}
if ((pid=fork()) < 0) {
perror ("Fork failed");
exit(errno);
}
if (! pid) {
close(pipe_fd[1]);
dup2(pipe_fd[0],0);
close(pipe_fd[0]);
if (execvp(argv[2],pargs) < 0) {
perror("Exec failed");
exit(errno);
}
} else {
size_t filedesc = open(argv[1],O_RDONLY);
while((n = read(filedesc, buf, 100)) > 0)
write (pipe_fd[1], buf, n);
while((n = read(0, buf, 100)) > 0)
write (pipe_fd[1], buf, n);
}
}
You can run your program with this wrapper as :
./wrapper input.txt myprog possible command line arguments
You can put your initial input into input.txt.
A simpler solution is to reopen the standard input. However if you simply try to open it as if you are opening a file, it does not work. You should open the terminal stream and copy it to standard input of your application. You can do it (again by using a wrapper) with something like:
size_t tty = open("/dev/tty",O_RDONLY);
dup2(tty,0);
Not to mention this second solution is for Linux and not portable.
In this example I use tail -f, not your C program
mkfifo /tmp/pipe # Open Pipe
tail -f /tmp/pipe & # Start your program and put it into the background
Now you also can send data to your program that runs in the background
echo "foobar" > /tmp/pipe
I hope this helps?
You could modify your program to accept 1 null character then continue on...it might work:
replace line 10 with something like
while (TRUE)
{
x = getchar();
if (x == '\n')
break;
if (x == '\0')
{
if (seen)
break;
seen = TRUE;
}
...

Resources