Home > Archive > PERL Beginners > January 2007 > exec and pipe
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
|
|
| Andreas Brillisauer - Hetzner Online AG 2007-01-19, 7:58 am |
| Hello,
I'm just writing a script that gets an email from stdin. This mail
should be passed to procmail via ssh. If calling ssh or procmail fails,
the mail should be saved locally.
First I tried to solve this with "system" or "open". But I cannot pipe
the mail to ssh when using "system". "open" can handle a pipe to ssh but
doesn't return the return value of ssh.
So I tried to create a pipe by my own using "pipe". After that I call
"fork". Then the mail is passed to ssh via the created pipe. But this
doesn't work.
Here is my current version of the script. For debugging reasons I call
"cat" instead of "ssh". But I get no output.
---8<---------------------------------------------------------------------
#!/usr/bin/perl
my $lb = $/;
$/ = undef;
my $mail = <STDIN>;
$/ = $lb;
my $pid;
pipe(READ, WRITE);
$pid = fork();
if ($pid == 0) {
close(WRITE);
exec('cat');
exit(1);
}
elsif ($pid > 0) {
close(READ);
my $old_handle = select(WRITE);
$| = 1;
print WRITE $mail;
waitpid($pid, WNOHANG);
$retval = $? >> 8;
select($old_handle);
print "$retval\n";
}
---8<---------------------------------------------------------------------
Thanks,
Andreas
| |
| Igor Sutton 2007-01-19, 7:58 am |
| Hi Andreas,
2007/1/19, Andreas Brillisauer - Hetzner Online AG
<andreas.brillisauer@hetzner.de>:
> Hello,
>
> I'm just writing a script that gets an email from stdin. This mail
> should be passed to procmail via ssh. If calling ssh or procmail fails,
> the mail should be saved locally.
>
> First I tried to solve this with "system" or "open". But I cannot pipe
> the mail to ssh when using "system". "open" can handle a pipe to ssh but
> doesn't return the return value of ssh.
>
> So I tried to create a pipe by my own using "pipe". After that I call
> "fork". Then the mail is passed to ssh via the created pipe. But this
> doesn't work.
>
> Here is my current version of the script. For debugging reasons I call
> "cat" instead of "ssh". But I get no output.
>
> ---8<---------------------------------------------------------------------
> #!/usr/bin/perl
>
> my $lb = $/;
> $/ = undef;
> my $mail = <STDIN>;
> $/ = $lb;
>
> my $pid;
>
> pipe(READ, WRITE);
>
> $pid = fork();
> if ($pid == 0) {
> close(WRITE);
> exec('cat');
> exit(1);
> }
> elsif ($pid > 0) {
> close(READ);
> my $old_handle = select(WRITE);
> $| = 1;
> print WRITE $mail;
> waitpid($pid, WNOHANG);
> $retval = $? >> 8;
> select($old_handle);
> print "$retval\n";
> }
> ---8<---------------------------------------------------------------------
I would suggest you using Net::SFTP[1] to transfer the file to remote
host, and then Net::SSH::Perl[2] to invoke procmail on remote host. I
think it is the best start, then you could improve it.
[1] http://search.cpan.org/~dbrobins/Ne...lib/Net/SFTP.pm
[2] http://search.cpan.org/~dbrobins/Ne...Net/SSH/Perl.pm
HTH!
--
Igor Sutton Lopes <igor.sutton@gmail.com>
| |
| nobull67@gmail.com 2007-01-19, 6:58 pm |
|
On Jan 19, 11:39 am, andreas.brillisa...@hetzner.de (Andreas
Brillisauer - Hetzner Online AG) wrote:
> Hello,
>
> I'm just writing a script that gets an email from stdin. This mail
> should be passed to procmail via ssh. If calling ssh or procmail fails,
> the mail should be saved locally.
>
> First I tried to solve this with "system" or "open". But I cannot pipe
> the mail to ssh when using "system". "open" can handle a pipe to ssh but
> doesn't return the return value of ssh.
Obviously open() cannot return the exit status because this would
require information to propagate backwards in time.#
On the other hand the exit status is put in $? close()ing the pipe.
> So I tried to create a pipe by my own using "pipe". After that I call
> "fork". Then the mail is passed to ssh via the created pipe. But this
> doesn't work.
>
> Here is my current version of the script. For debugging reasons I call
> "cat" instead of "ssh". But I get no output.
>
> ---8<---------------------------------------------------------------------
> #!/usr/bin/perl
>
> my $lb = $/;
> $/ = undef;
> my $mail = <STDIN>;
> $/ = $lb;
Consider using local()
> my $pid;
>
> pipe(READ, WRITE);
>
> $pid = fork();
> if ($pid == 0) {
> close(WRITE);
> exec('cat');
> exit(1);
> } elsif ($pid > 0) {
> close(READ);
> my $old_handle = select(WRITE);
> $| = 1;
> print WRITE $mail;
> waitpid($pid, WNOHANG);
You have not closed WRITE so the child process will still just be
sitting there reading the other end of the pipe. You cannot therefore
read its exit status because, once again, you are trying to make
information travel backwards in time.
Even if you do close(WRITE) the WNOHANG will create a race condition. A
race that you'll almost certainly loose (i.e. waitpid() will almost
certainly fail).
| |
| Jenda Krynicky 2007-01-22, 6:58 pm |
| From: Andreas Brillisauer - Hetzner Online AG <andreas.brillisauer@hetzner.de>
> Hello,
>
> I'm just writing a script that gets an email from stdin. This mail
> should be passed to procmail via ssh. If calling ssh or procmail
> fails, the mail should be saved locally.
>
> First I tried to solve this with "system" or "open". But I cannot pipe
> the mail to ssh when using "system". "open" can handle a pipe to ssh
> but doesn't return the return value of ssh.
Maybe because by the time oepn() returns it only knows whether it was
able to start the process. And since the process does and needs to
run for some more time open() can't return the return value. but
close() can:
perldoc -f close
close FILEHANDLE
close Closes the file or pipe associated with the file handle,
returning true only if IO buffers are successfully flushed and
closes the system file descriptor. Closes the currently selected
filehandle if the argument is omitted.
You don't have to close FILEHANDLE if you are immediately going
to do another "open" on it, because "open" will close it for
you. (See "open".) However, an explicit "close" on an input file
resets the line counter ($.), while the implicit close done by
"open" does not.
If the file handle came from a piped open, "close" will
additionally return false if one of the other system calls
involved fails, or if the program exits with non-zero status.
(If the only problem was that the program exited non-zero, $!
will be set to 0.) Closing a pipe also waits for the process
executing on the pipe to complete, in case you want to look at
the output of the pipe afterwards, and implicitly puts the exit
status value of that command into $?.
HTH, Jenda
===== Jenda@Krynicky.cz === http://Jenda.Krynicky.cz =====
When it comes to wine, women and song, wizards are allowed
to get drunk and croon as much as they like.
-- Terry Pratchett in Sourcery
|
|
|
|
|