I have a Perl script which runs as a background process on an e-mail server and attempts to detect compromised e-mail accounts through various checks on the queue and log files. I added a handler for the USR1 signal which causes the script to print some information about itself while it's running. This works great if I start the script in the background and then send the USR1 signal, like so:
./myscript.pl & kill -USR1 (PID)
The problem is, if I exit that shell session and then connect in again, I can't get any output when I use the kill -USR1
command anymore because the TTY associated with STDOUT for the script is gone.
So, I'm wondering if there is a way to get the TTY of the user or shell process which sent a signal in Perl, and then direct output back to the TTY instead of STDOUT. I tried using POSIX::ttyname(1)
in the signal handler, but it returns the TTY of the script's STDOUT (which is an empty value in this case), not the TTY of the user who sent the USR1 signal.
I saw in the Perldoc for POSIX that POSIX::sigaction
will give the PID and UID of the process which generated the signal, but I don't know if there's a good way to get the TTY name from that information in Perl.
Any help would be greatly appreciated! Thanks!
The simplest solution is the one proposed by nab in a comment to your question: just log your output to a file (possibly in your $SIG{USR1} handler), and then monitor that. You could even overwrite it each time you get a SIGUSR1.
Another solution, which I've got running, is to create a socket handler. This gets a bit more convoluted, unless you're willing to use a bunch of modules. My solution is to use AnyEvent + Coro. I put the main work in one Coro thread, start up my AnyEvent::Socket::tcp_server(s) (socket and/or tcp port number), and, on connection, do what I need to do (in my case, create a bunch of threads, in your case just output the details like you do in your $SIG{USR1} handler, and close the connection).
Real code:
AnyEvent::Socket::tcp_server "unix/", "/tmp/cbstats.sock", sub {
my $fh = shift;
$fh->binmode(':utf8');
$fh = unblock $fh;
$self->handle_connection($fh, @_);
};
And then, because mine is interactive, I run socat readline /tmp/cbstats.sock
. In your case, you could just do socat stdout /tmp/your.socket
any time you wanted the output. (Use filesystem permissions to restrict/allow who can see this data.)
There's a little bit to concern yourself here - you'll need to stop using sleep() (or use the Coro version) so that you can receive requests on the socket. But, to be honest, it's been mostly minimal. I have, however, switched my server over to using AnyEvent timers, then I don't even need to worry about sleeping. After that, I smooshed multiple servers together on their own timers, and it has all worked fairly well.
Good luck.