PDA

View Full Version : C - Continuously analyze of standard output from other program



lifedj87
July 9th, 2011, 05:50 PM
I have to create a program that do this

start another existing program
capture the standard output of the previos program and depending on what it print, it do something else.

I will try to explain the situation with an example:

Let's think that I have a program (example.c) that print a sequence of number (from 1 to 1000).
I have to create a program that start the "example.c" program and read the output continuously, so, when it print the number 348, it stop the example program!

I could separate the two processes (caller and example) with a fork, but I don't know how to analyze continuously the output!

Is there someone that can help me?

Thank you very much!

Arndt
July 9th, 2011, 08:40 PM
I have to create a program that do this

start another existing program
capture the standard output of the previos program and depending on what it print, it do something else.

I will try to explain the situation with an example:

Let's think that I have a program (example.c) that print a sequence of number (from 1 to 1000).
I have to create a program that start the "example.c" program and read the output continuously, so, when it print the number 348, it stop the example program!

I could separate the two processes (caller and example) with a fork, but I don't know how to analyze continuously the output!

Is there someone that can help me?

Thank you very much!

Have you been told about pipes?

lifedj87
July 10th, 2011, 03:29 PM
No, I've never studied it!
Thank you for the help! I will look for pipes and I will ask you something else if necessary! ;-)

lifedj87
July 11th, 2011, 05:41 PM
I'm near the right solution, but the program i've created doesn't work properly!
I would pause the parent process when it print the number 345, but it doesn't do it: if i print all the output, after the line "Process stopped" it print all the other numbers!

I think that the problem is that it doesn't anayze the output as a runtime, but that it analyze it only after the end of the execution.
Is there someone who can help me?

This is the code:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

int main() {

int pdes[2];

pipe(pdes);

int r = fork();

if (r == -1)
{
/* errore */
printf("Errore nella fork!\n");

}
else if(r == 0)
{
/* son */
close(pdes[1]);
char buf[20];
size_t nbytes;
ssize_t bytes_read;
nbytes = sizeof(buf);
bytes_read = read(pdes[0], buf, nbytes);
char string_to_recognize[]="345";
int j=0;
int l=0;
int ok=0;
int indice=1;
int found=0;
while(bytes_read = read(pdes[0], buf, nbytes))
{
int i;
for(i = 0; i < 20;i++)
{
if ((buf[i] == string_to_recognize[0]) && (found!=1))
{
j=1;
ok=1;
}
if ((ok!=1) && (found!=1))
{
if (buf[i] == string_to_recognize[j])
{
j++;
ok=1;
}
else
{
j=0;
}
}
if (j==(sizeof(string_to_recognize)-1))
{

/* after the identification of the string, count 10 letters and then bring the process in pause*/
if (l==10)
{
int id_proc=getppid(); /* get parent id */
//execlp("kill", "KILL", "-SIGSTOP "+id_proc, NULL);
signal(SIGTSTP, SIG_DFL); /* reset disposition to default */

kill(id_proc, SIGTSTP); /*process pause */
}
l++;
//j=0;
found=1;
}
//printf("%c",buf[i]);
ok=0;
}
}
if (found ==1)
{
l++;
/* after the pause, count 10000-10 letters and then i restart the process*/

//if (l==10000)
//{
// int id_proc=getppid(); /* get the parent id*/
// kill(id_proc, SIGCONT); /*restart the process */
//
//}
}
}
else
{
/* parent code */
close(pdes[0]);
dup2(pdes[1], STDOUT_FILENO);
execlp("/home/lifedj/progetto/comando.sh", "./comando.sh", "", NULL);
}
return 0;
}

Bachstelze
July 11th, 2011, 06:02 PM
What does your .sh script do? Most likely the problem is that between the moment your program detects the target string and the moment the target program is actually killed, it will still be running and outputting text. With this program:


#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv, char **envp) {

int pdes[2];

if (pipe(pdes) != 0) {
perror("Couldn't create the pipe");
exit(EXIT_FAILURE);
}

int r = fork();
if (r == -1) {
perror("Couldn't fork");
exit(EXIT_FAILURE);
} else if (r == 0) {
/* Child */
close(pdes[1]);
dup2(pdes[0], STDIN_FILENO);
char buf[20];
char target[] = "350";
FILE *ofile = fopen("output.txt", "w");
while (fgets(buf, 20, stdin) != NULL) {
fputs(buf, ofile);
/* Remove the newline so that it does not interfere with strncmp() */
if (buf[strlen(buf) - 1] == '\n') {
buf[strlen(buf) - 1] = 0;
}

if (strncmp(buf, target, 20) == 0) {
fputs("Target number found!\n", ofile);
int ppid = getppid();
kill(ppid, SIGINT);
}
}
fclose(ofile);
} else {
/* Parent */
close(pdes[0]);
dup2(pdes[1], STDOUT_FILENO);
execve("./sequence", argv, envp);
}
return 0;
}


And sequence being this:


#include <stdio.h>

int main(void)
{
int i=0;
for (;;) {
printf("%d\n", i++);
}
return 0;
}


I get the numbers up to about 3500 in output.txt, so it means that the process does get killed, just not right after the target string is detected. I don't think there is a way to make it terminate right away without modifying its code.

lifedj87
July 11th, 2011, 06:31 PM
Symply print a sequence of 1000 numbers from 0 to 999!

Bachstelze
July 11th, 2011, 06:44 PM
Symply print a sequence of 1000 numbers from 0 to 999!

Then just make it indefinitely output numbers as I did above and you will see it does eventually terminate. ;)

lifedj87
July 11th, 2011, 09:21 PM
I haven't seen your answer!
I will try immediately!
Thank you!!!

Another question: if I want to resume the process from pause after x seconds, how I have to modify your code?

lifedj87
July 11th, 2011, 09:39 PM
I've just tried your code: the error is the same:
Even if the code works, if i try to add

fputs(buf, stderr);

after
fputs(buf, ofile);

It prints all the numbers (from 350 to 999), so the problem is not solved: the program execcute all the script and then it analyzes the output! Is there a way to do it simultaneosly?
The only modification that I did to your code is that I continue to use execlp instead of execve because I can't let it work with execve (if I try to compile and then execute the program, it doesn't start the script thet you call sequence!

Could it be the reason why the code doesn't work?

PS. Thank you for your help!

Bachstelze
July 11th, 2011, 09:49 PM
It prints all the numbers (from 350 to 999), so the problem is not solved: the program execcute all the script and then it analyzes the output! Is there a way to do it simultaneosly?

Did you read what I said? Between the moment you run kill() and the moment the process is actually killed, there is a lot of time during which the process is still running and outputting text. There no way to kill the process immediately (that I know of, and I would be very surprised if there were).

lifedj87
July 12th, 2011, 11:28 AM
Ah, ok! I didn't undestand!
Thank you very much!

However: if I would like to resume the process from pause, where I have to modify the code?
I would like to pause it and then restart after x seconds!

Bachstelze
July 12th, 2011, 11:49 AM
Just replace


kill(ppid, SIGINT);

with something like


kill(ppid, SIGSTOP);
sleep(10);
kill(ppid, SIGCONT);

lifedj87
July 12th, 2011, 07:03 PM
Ok, i will try! Thank you very much!!! ;-)