2010-01-19 11 views
6

Tengo un módulo que utiliza IPC :: Open3 (o IPC :: Open2, ambos presentan este problema) para llamar a un binario externo (bogofilter en este caso) y se alimentan a través de una cierta entrada el identificador de archivos de entrada de elementos secundarios, luego lee el resultado del manejador de salida de elementos secundarios. El código funciona bien cuando se ejecuta en la mayoría de los entornos. Sin embargo, el uso principal de este módulo está en un servicio web que se ejecuta bajo Apache 2.2.6. Y bajo ese ambiente, me sale el error:IPC :: Open3 Fails corre sobre Apache

No se puede fdopen STDOUT: argumento no válido

Esto sólo ocurre cuando el código se ejecuta en Apache. Anteriormente, el código construía un comando horriblemente complejo, que incluía un documento aquí para la entrada, y lo ejecutaba con "back-ticks". Eso funcionó, pero fue muy lento y propenso a romper formas únicas y desconcertantes. Odiaría tener que volver a la versión anterior, pero no puedo descifrar esto.

Respuesta

1

Podría ser porque mod_perl 2 cierra la salida estándar? Acabo de descubrir esto y publicado al respecto:

http://marc.info/?l=apache-modperl&m=126296015910250&w=2 

creo que es un error desagradable, pero nadie parece preocuparse por ello hasta el momento. Publique un seguimiento en la lista mod_perl si su problema está relacionado y desea que llame la atención.

Jon

+0

¡Creo que estás en el camino correcto! – Ryley

0

Bogofilter regresa diferentes códigos de salida para spam/nonspam.

Usted puede "arreglar" esta redirigiendo la salida estándar a/dev/null

system("bogofilter < $input > /dev/null") >> 8; 

devolverá 0 para el correo no deseado, 1 para nonspam, 2 para desconocida (la >> 8 es porque Perl amablemente corrige la salida código, esto corrige el daño).

Nota: la falta de un entorno también puede prevenir bogofilter de encontrar su lista de palabras, por lo que pasará en forma explícita así:

system("bogofilter -d /path/to/.bogofilter/ < $input > /dev/null") >> 8; 

(donde /path/to/.bogofilter contiene el wordlist.db)

no se puede recuperar la calificación real que bogofilter dio de esa manera, pero se vuelve algo.

+0

No creo que ese sea el problema directo aquí, si es necesario usar Open3 específicamente. – Ryley

0

Si el código es sólo va a ser ejecutado en sistemas Linux/Unix es fácil escribir un reemplazo open3 que no falla, porque la salida estándar no es un identificador de archivo real:

sub my_open3 { 
    # untested! 
    pipe my($inr), my($inw) or die; 
    pipe my($outr), my($outw) or die; 
    pipe my($errr), my($errw) or die; 
    my $pid = fork; 
    unless ($pid) { 
     defined $pid or die; 
     POSIX::dup2($inr, 0); 
     POSIX::dup2($outw, 1); 
     POSIX::dup2($errw, 2); 
     exec @_; 
     POSIX::_exit(1); 
    } 
    return ($inw, $outr, $errr); 
} 

my ($in, $out, $err) = my_open3('ls /etc/'); 
0

caveat.emptor: I no soy un mago perl.

Como sugirió @JonathanSwartz, creo que el problema es que apache2 mod_perl cierra entrada y salida estándar. Eso no debería ser relevante para lo que IPC :: Open3 está haciendo, pero tiene un error en él, described here.

En resumen (esta es la parte en la que no estoy muy claro), open3 intenta hacer coincidir los procesos hijo STDIN/OUT/ERR en su proceso, o lo duplica si eso fue lo que se solicitó. Debido a algunas formas indocumentados que se abren ('> & = X') funciona, por lo general funciona bien, excepto en el caso en STDIN/OUT/ERR están cerrados.

Another link que se interna en los detalles.

Una solución es reparar IPC :: Open3, como se describe en ambos enlaces. El otro, que trabajó para mí, es abrir temporalmente STDIN/OUT en el código mod_perl y luego cerrarla después:

my ($save_stdin,$save_stdout); 
open $save_stdin, '>&STDIN'; 
open $save_stdout, '>&STDOUT'; 
open STDIN, '>&=0'; 
open STDOUT, '>&=1'; 

#make your normal IPC::Open3::open3 call here 

close(STDIN); 
close(STDOUT); 
open STDIN, '>&', $save_stdin; 
open STDOUT, '>&', $save_stdout; 

Además, me di cuenta de un montón de quejas en torno a la red acerca de IPC :: Run3 que sufren de los mismos problemas, así que si alguien se encuentra con el mismo problema, sospecho que la misma solución funcionaría.