Escopo de variavel em fork

1. Escopo de variavel em fork

Mauricio Souza Klein
Hebang

(usa Arch Linux)

Enviado em 19/10/2011 - 16:55h

Olá pessoal!

Estou fazendo um método que executa um comando externo e retorna o status de saida do comando (i.e. status do pclose) e a saida padrão do comando (i.e. leitura do FILE* associado ao popen).

Além disso, criei um sistema de timeout, para caso o popen leve mais de 'timeout' segundos para executar, o processo filho é abortado e a saida é '3'.

A questão é:
Minha saida padrão deve ser salva na string 'output' passada por referência na chamada da função 'my_system'.
Porém, não importa o que eu escreva nessa string, depois da chamada ela é sempre vazia.

Segue as funções que estou utilizado:


#include <string>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <syslog.h>

#include "execute.h"
#include "path.h"

#define BUFFER_SIZE 4096

using namespace std;

void sighandler(int sig)
{
// force the child process to exit...
syslog( LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Aborting request execution by timeout!" );
exit(3);
}

int my_system(const string &command, unsigned int timeout, string &output)
{
pid_t pid = fork();

/* Falhou o fork */
if( pid < 0 ){
syslog( LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Failed to create fork! Aborting plugin execution..." );
output = "Could not execute plugin: fork failed!";
return 3; // Unknown
}

/* Processo pai */
if( pid > 0 ){
int status;

if( wait(&status) == -1 ){
syslog( LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Could not retrieve the child process status!" );
output = "Could not execute plugin: failed to retrieve process status";
}
else{
/* Execucao OK */
if( WIFEXITED(status) )
return WEXITSTATUS(status);
/* Execucao abortada por sinal */
else if( WIFSIGNALED(status) ){
output = "Could not execute plugin: execution aborted by signal (probably timeout)";
return WTERMSIG(status);
}
}

/*
Se chegar aqui, ou nao pode dispara o wait
ou nao sabe como pegar o status de saida do child
*/
return 3;
}

/* Processo filho, que ira executar o popen */
else{
FILE* fp = NULL;
output = "";
int returnValue;
unsigned int tries = 0;

/*
Se em 'timeout' segundos o plugin nao terminar
sua execucar, desvia para o 'sighandler'
e retorna 3 (i.e. UNKNOWN)
*/
signal(SIGALRM, sighandler);
alarm (timeout);

char* final_command = (char*)malloc( BUFFER_SIZE * sizeof(char) );
if( !final_command ){
syslog( LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Could not create the command line!" );
returnValue = -1;
goto finish;
}

/*
Final Command = Command + [Redirect of 'stderr' to /dev/null]
*/
sprintf( final_command, "%s 2> /dev/null", command.c_str() );

do{
// run the command
fp = popen( final_command, "r" );

output = "";

/*
Retorna erro se nao foi possivel rodar o comando,
ou le a saida do comando em caso de sucesso.
*/
if( fp == NULL ){
syslog( LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "command could not be executed: %s", command.c_str() );
returnValue = -1;
}
else{
char buffer[ BUFFER_SIZE ];

while( fgets( buffer, BUFFER_SIZE, fp ) != NULL )
output += buffer;

returnValue = pclose( fp );
}
}
while( tries++ < 6 && ( returnValue < 0 || returnValue > 3 ) );

/*
Em alguns sistemas o pclose retorna
o status de saida do comando executado
na parte alta da palavra.

Logo, se a saida do pclose for maior que 3 (valor maximo do plugin),
divide por 256 para colocar na parte baixa.
*/
if( returnValue > 3 )
returnValue /= 256;

finish:
exit(returnValue);
}

return 3;
}


Como podem ver, a variavel 'output' eh escrita tanto no processo pai quanto no filho.
Porém, mesmo a execução retornando de forma natural quanto forçando a saida por timeout, o 'output' eh sempre vazio.

Jah me certifiquei e o status de saida está 100% OK, o único problema é o 'output'.

Desde já, grato por qualquer idéia postada.


  






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts