150 lines
3.9 KiB
Plaintext
150 lines
3.9 KiB
Plaintext
|
#!/usr/bin/perl -w
|
||
|
# LiveJournal Remote Procedure Call Daemon (ljrpcd)
|
||
|
# Copyright 2001 Dormando (dormando@rydia.net)
|
||
|
# Going add a license (GPL?) later.
|
||
|
# This daemon forks off into the background, logs if told to
|
||
|
# waits for UDP messages on the given port, and executes
|
||
|
# commands sent to it.
|
||
|
#
|
||
|
# <LJDEP>
|
||
|
# lib: IO::Socket
|
||
|
# prog: bin/ljmaint.pl
|
||
|
# </LJDEP>
|
||
|
|
||
|
use strict;
|
||
|
use IO::Socket;
|
||
|
|
||
|
# Max message length and port to bind.
|
||
|
my $MAXLEN = 512;
|
||
|
my $PORTNO = 6100;
|
||
|
my $PIDFILE = '/var/run/ljrpcd.pid';
|
||
|
my $LOGFILE = '/var/log/ljrpcd.log';
|
||
|
my $TYPE = shift @ARGV;
|
||
|
|
||
|
unless ($TYPE eq "web" || $TYPE eq "db") {
|
||
|
print "Unknown/unspecified machine type, quitting.\n";
|
||
|
exit 1;
|
||
|
}
|
||
|
|
||
|
# Pid and pidfile.
|
||
|
my $pid;
|
||
|
my $is_parent = 1;
|
||
|
# Socket. Needs to be here for the HUP stuff.
|
||
|
my $sock;
|
||
|
|
||
|
# In case we're shot, unlink the pidfile.
|
||
|
$SIG{TERM} = sub {
|
||
|
unlink($PIDFILE);
|
||
|
exit 1;
|
||
|
};
|
||
|
|
||
|
if (-e $PIDFILE) {
|
||
|
open (PID, $PIDFILE);
|
||
|
my $tpid;
|
||
|
chomp ($tpid = <PID>);
|
||
|
close PID;
|
||
|
|
||
|
if ($tpid) {
|
||
|
# so Linux-specific, but Proc::ProcessTable
|
||
|
#iterates over /dev forever, which sucks on a NetApp
|
||
|
if (open (CMD, "/proc/$tpid/cmdline")) {
|
||
|
my $cmdline = <CMD>;
|
||
|
close CMD;
|
||
|
if ($cmdline =~ /ljrpcd/) {
|
||
|
print "Process exists already, quitting.\n";
|
||
|
exit 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Print a banner.
|
||
|
print "LiveJournal RPC Daemon starting up into the background...\n";
|
||
|
|
||
|
# Perhaps I should give it a command to not do this in the future.
|
||
|
if ($pid = fork) {
|
||
|
# Parent, log pid and exit.
|
||
|
open(PID, ">$PIDFILE") or die "Couldn't open $PIDFILE for writing: $!\n";
|
||
|
print PID $pid;
|
||
|
close(PID);
|
||
|
print "Closing ($pid) wrote to $PIDFILE\n";
|
||
|
$is_parent = 1;
|
||
|
exit;
|
||
|
} else {
|
||
|
# This is the child, main loop-de-doo.
|
||
|
my($cmdmsg, $remaddr, $remhost);
|
||
|
|
||
|
# HUP signal handler.
|
||
|
$SIG{HUP} = \&restart_request;
|
||
|
|
||
|
open(LOG, ">>$LOGFILE") or die "Couldn't open log file for appending: $!\n";
|
||
|
flock(LOG, 2) or die "Couldn't flock log file for writing: $!\n";
|
||
|
select(LOG); # Why the hell not, eh?
|
||
|
$| = 1;
|
||
|
|
||
|
$sock = IO::Socket::INET->new(LocalPort => "$PORTNO", Proto => 'udp') or die "socket: $@";
|
||
|
$sock->sockopt(SO_BROADCAST, 1);
|
||
|
print "Bound, awaiting UDP commands on port $PORTNO\n";
|
||
|
|
||
|
# Main loop, simple parser.
|
||
|
while ($sock->recv($cmdmsg, $MAXLEN)) {
|
||
|
my ($port, $ipaddr) = sockaddr_in($sock->peername);
|
||
|
my $ip_addy = inet_ntoa($ipaddr);
|
||
|
|
||
|
$remhost = gethostbyaddr($ipaddr, AF_INET);
|
||
|
print "Client $remhost sent command: $cmdmsg\n";
|
||
|
|
||
|
# If the command is 'marco' return 'pollo'
|
||
|
if ($cmdmsg =~ /^marco(\s+($TYPE|all))?$/) {
|
||
|
print "Returning 'pollo' to client $remhost\n";
|
||
|
$sock->send("pollo") or print "Couldn't scream pollo at $remhost\n";
|
||
|
next;
|
||
|
} elsif ($cmdmsg =~ s/^cmd:\s//) {
|
||
|
# Handle the command.
|
||
|
if ($cmdmsg eq "restart") {
|
||
|
print "Restarting ljrpcd\n";
|
||
|
$sock->send("Restarting ljrpcd...\n");
|
||
|
restart_request();
|
||
|
}
|
||
|
my $return = handle_request($cmdmsg);
|
||
|
print "Returning $return to client $remhost\n";
|
||
|
$sock->send($return) or print "Couldn't return $return to $remhost\n";
|
||
|
next;
|
||
|
}
|
||
|
}
|
||
|
die "recv: $!\n";
|
||
|
} #if
|
||
|
|
||
|
# Sub to restart the daemon.
|
||
|
sub restart_request {
|
||
|
$sock->close;
|
||
|
unlink($PIDFILE);
|
||
|
exec($0, $TYPE);
|
||
|
}
|
||
|
|
||
|
|
||
|
# Handle a request... Do further parsing, pass it appropriately.
|
||
|
# Should return a discernable ok. Usually 'done' 'ok' or an
|
||
|
# informative reply no longer than 500 characters.
|
||
|
sub handle_request {
|
||
|
my $cmd = shift;
|
||
|
my $su = "";
|
||
|
if ($cmd =~ s/^(\w+?)://) {
|
||
|
my $user = $1;
|
||
|
my ($login,$pass,$uid,$gid) = getpwnam($user)
|
||
|
or return "$user not in passwd file.";
|
||
|
$su = "su $user -c";
|
||
|
}
|
||
|
unless ($cmd =~ /[\|\>\<]/) {
|
||
|
my $home = $ENV{'LJHOME'} || "/home/lj";
|
||
|
$cmd =~ s/[;]/\\$&/;
|
||
|
if ($su) {
|
||
|
return `$su \'$home/bin/ljmaint.pl $cmd\'`;
|
||
|
} else {
|
||
|
return `$home/bin/ljmaint.pl $cmd`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 'bad command';
|
||
|
}
|