| 1 |
weasel |
158 |
#!/usr/bin/perl -w |
| 2 |
weasel |
1 |
|
| 3 |
weasel |
138 |
$| = 1; |
| 4 |
|
|
|
| 5 |
weasel |
1 |
# (c) 2002 Peter Palfrader <peter@palfrader.org> |
| 6 |
weasel |
161 |
# $Id: pingd,v 1.38 2002/07/12 00:44:23 weasel Exp $ |
| 7 |
weasel |
1 |
# |
| 8 |
|
|
|
| 9 |
weasel |
54 |
=pod |
| 10 |
|
|
|
| 11 |
|
|
=head1 NAME |
| 12 |
|
|
|
| 13 |
|
|
pingd - echolot ping daemon |
| 14 |
|
|
|
| 15 |
|
|
=head1 SYNOPSIS |
| 16 |
|
|
|
| 17 |
|
|
=over |
| 18 |
|
|
|
| 19 |
|
|
=item B<pingd> B<start> |
| 20 |
|
|
|
| 21 |
|
|
=item B<pingd> B<stop> |
| 22 |
|
|
|
| 23 |
weasel |
88 |
=item B<pingd> B<process> |
| 24 |
|
|
|
| 25 |
weasel |
75 |
=item B<pingd> B<add> I<address> [I<address> ...] |
| 26 |
weasel |
54 |
|
| 27 |
weasel |
94 |
=item B<pingd> B<delete> I<address> [I<address> ...] |
| 28 |
|
|
|
| 29 |
weasel |
75 |
=item B<pingd> B<set> option=value [option=value..] I<address> [I<address> ...] |
| 30 |
|
|
|
| 31 |
weasel |
103 |
=item B<pingd> B<setremailercaps> I<capsstring> |
| 32 |
|
|
|
| 33 |
|
|
=item B<pingd> B<deleteremailercaps> I<address> |
| 34 |
|
|
|
| 35 |
weasel |
94 |
=item B<pingd> B<getkeyconf> |
| 36 |
|
|
|
| 37 |
weasel |
81 |
=item B<pingd> B<dumpconf> |
| 38 |
|
|
|
| 39 |
weasel |
54 |
=back |
| 40 |
|
|
|
| 41 |
|
|
=head1 DESCRIPTION |
| 42 |
|
|
|
| 43 |
|
|
pingd is a the heart of echolot. Echolot is a pinger for anonymous remailers. |
| 44 |
|
|
|
| 45 |
|
|
A Pinger in the context of anonymous remailers is a program that regularily |
| 46 |
|
|
sends messages through remailers to check their reliability. It then calculates |
| 47 |
|
|
reliability statistics which are used by remailer clients to choose the chain |
| 48 |
|
|
of remailers to use. |
| 49 |
|
|
|
| 50 |
|
|
Additionally it collects configuration parameters and keys of all remailers and |
| 51 |
|
|
offers them in a format readable by remailer clients. |
| 52 |
|
|
|
| 53 |
|
|
When called without parameters pingd schedules tasks like sending pings, |
| 54 |
|
|
processing incoming mail and requesting remailer-xxx data and runs them in |
| 55 |
|
|
configurable intervalls. |
| 56 |
|
|
|
| 57 |
|
|
=head1 COMMANDS |
| 58 |
|
|
|
| 59 |
|
|
=over |
| 60 |
|
|
|
| 61 |
|
|
=item B<start> |
| 62 |
|
|
|
| 63 |
|
|
Start the ping daemon. |
| 64 |
|
|
|
| 65 |
|
|
=item B<stop> |
| 66 |
|
|
|
| 67 |
|
|
Send the running pingd process a SIGTERM. |
| 68 |
|
|
|
| 69 |
weasel |
88 |
=item B<process> |
| 70 |
|
|
|
| 71 |
|
|
Sends a HUP signal to the daemon which instructs it to process the commands. |
| 72 |
|
|
|
| 73 |
|
|
For other affects of sending the HUP Signal see the SIGNALS section below. |
| 74 |
|
|
|
| 75 |
weasel |
75 |
=item B<add> I<address> [I<address> ...] |
| 76 |
weasel |
54 |
|
| 77 |
|
|
Add I<address> to the list of remailers to query for |
| 78 |
|
|
keys and confs. |
| 79 |
|
|
|
| 80 |
weasel |
94 |
=item B<delete> I<address> [I<address> ...] |
| 81 |
|
|
|
| 82 |
|
|
Delete I<address> from the list of remailers to query for |
| 83 |
weasel |
128 |
keys and confs. Delete all statistics and keys for that remailer. |
| 84 |
weasel |
94 |
|
| 85 |
weasel |
75 |
=item B<set> option=value [option=value..] I<address> [I<address> ...] |
| 86 |
|
|
|
| 87 |
|
|
Possible options and values: |
| 88 |
|
|
|
| 89 |
|
|
=over |
| 90 |
|
|
|
| 91 |
|
|
=item B<showit=>{B<on>,B<off>} |
| 92 |
|
|
|
| 93 |
|
|
Set B<showit> (show remailer in mlist, rlist etc.) for remailer I<address> to |
| 94 |
|
|
either B<on> or B<off>. |
| 95 |
|
|
|
| 96 |
|
|
=item B<pingit=>{B<on>,B<off>} |
| 97 |
|
|
|
| 98 |
|
|
Set B<pingit> (send out pings to that remailer) for remailer I<address> to |
| 99 |
|
|
either B<on> or B<off>. |
| 100 |
|
|
|
| 101 |
|
|
=item B<fetch=>{B<on>,B<off>} |
| 102 |
|
|
|
| 103 |
|
|
Set B<fetch> (fetch remailer-key and remailer-conf) for remailer I<address> to |
| 104 |
|
|
either B<on> or B<off>. |
| 105 |
|
|
|
| 106 |
|
|
=back |
| 107 |
|
|
|
| 108 |
weasel |
103 |
=item B<setremailercaps> I<capsstring> |
| 109 |
|
|
|
| 110 |
|
|
Some remailers (Mixmaster V2 - currently lcs and passthru2) don't return a |
| 111 |
|
|
useable remailer-conf message. For such remailers you need to set it manually. |
| 112 |
|
|
|
| 113 |
|
|
For instance: |
| 114 |
|
|
|
| 115 |
|
|
./pingd setremailercaps '$remailer{"passthru2"} = "<mixer@immd1.informatik.uni-erlangen.de> mix middle";' |
| 116 |
|
|
./pingd setremailercaps '$remailer{"lcs"} = "<mix@anon.lcs.mit.edu> mix klen1000";' |
| 117 |
|
|
|
| 118 |
|
|
=item B<deleteremailercaps> I<address> |
| 119 |
|
|
|
| 120 |
|
|
Delete remailer-conf data for I<address>. The config data will be reset from |
| 121 |
|
|
the next valid remailer-conf reply by the remailer. |
| 122 |
|
|
|
| 123 |
weasel |
94 |
=item B<getkeyconf> |
| 124 |
|
|
|
| 125 |
|
|
Send a command to immediatly request keys and configuration from remailers. |
| 126 |
|
|
|
| 127 |
weasel |
81 |
=item B<dumpconf> |
| 128 |
|
|
|
| 129 |
|
|
Dumps the current configuration to standard output. |
| 130 |
|
|
|
| 131 |
weasel |
103 |
=back |
| 132 |
|
|
|
| 133 |
weasel |
54 |
=head1 OPTIONS |
| 134 |
|
|
|
| 135 |
weasel |
81 |
=over |
| 136 |
weasel |
54 |
|
| 137 |
weasel |
81 |
=item --verbose |
| 138 |
|
|
|
| 139 |
|
|
Verbose mode. Causes B<pingd> to print debugging messages about its progress. |
| 140 |
|
|
|
| 141 |
|
|
=item --help |
| 142 |
|
|
|
| 143 |
|
|
Print a short help and exit sucessfully. |
| 144 |
|
|
|
| 145 |
weasel |
117 |
=item --version |
| 146 |
|
|
|
| 147 |
|
|
Print version number and exit sucessfully. |
| 148 |
|
|
|
| 149 |
weasel |
94 |
=item --nohup |
| 150 |
weasel |
88 |
|
| 151 |
weasel |
128 |
Usefull only with the B<add>, B<set>, B<setremailercaps>, |
| 152 |
weasel |
103 |
B<deleteremailercaps> or B<getkeyconf> command. |
| 153 |
weasel |
88 |
|
| 154 |
weasel |
94 |
Don't send a HUP signal to the daemon which instructs it to process the |
| 155 |
|
|
commands after adding the command to the task list. |
| 156 |
weasel |
88 |
|
| 157 |
weasel |
94 |
Per default such a signal is sent. |
| 158 |
|
|
|
| 159 |
weasel |
127 |
=item --process |
| 160 |
|
|
|
| 161 |
weasel |
128 |
Usefull only with the B<start> command. |
| 162 |
weasel |
127 |
|
| 163 |
|
|
Read and process the commands file on startup. |
| 164 |
|
|
|
| 165 |
weasel |
88 |
=item --detach |
| 166 |
|
|
|
| 167 |
weasel |
128 |
Usefull only with the B<start> command. |
| 168 |
weasel |
88 |
|
| 169 |
|
|
Tell B<pingd> to detach. |
| 170 |
|
|
|
| 171 |
weasel |
54 |
=back |
| 172 |
|
|
|
| 173 |
|
|
=head1 FILES |
| 174 |
|
|
|
| 175 |
weasel |
115 |
The configuration file is searched in those places in that order: |
| 176 |
weasel |
54 |
|
| 177 |
weasel |
115 |
=over |
| 178 |
|
|
|
| 179 |
|
|
=item the file pointed to by the B<ECHOLOT_CONF> environment variable |
| 180 |
|
|
|
| 181 |
|
|
=item `pwd`/pingd.conf |
| 182 |
|
|
|
| 183 |
|
|
=item $HOME/echolot/pingd.conf |
| 184 |
|
|
|
| 185 |
|
|
=item $HOME/pingd.conf |
| 186 |
|
|
|
| 187 |
|
|
=item $HOME/.pingd.conf |
| 188 |
|
|
|
| 189 |
|
|
=item /etc/pingd.conf |
| 190 |
|
|
|
| 191 |
|
|
=back |
| 192 |
|
|
|
| 193 |
weasel |
88 |
=head1 SIGNALS |
| 194 |
|
|
|
| 195 |
weasel |
103 |
On B<SIGINT>, B<SIGQUIT>, and B<SIGTERM> B<pingd> will schedule a shutdown |
| 196 |
|
|
for as soon as the current actions are finished or immediatly if no actions are |
| 197 |
|
|
currently beeing processed. It will then write all metadata and pingdata to |
| 198 |
weasel |
88 |
disk and close all files cleanly before exiting. |
| 199 |
|
|
|
| 200 |
|
|
On B<SIGHUP> <pingd> will execute any pending commands from the commands file |
| 201 |
|
|
(B<commands.txt> per default). It also closes and reopens the file 'output' |
| 202 |
|
|
which is used for stdout and stderr in case the daemon was told to detach. |
| 203 |
|
|
This can be used if you want to rotate that file. |
| 204 |
|
|
|
| 205 |
weasel |
54 |
=head1 AUTHOR |
| 206 |
|
|
|
| 207 |
weasel |
103 |
Peter Palfrader E<lt>peter@palfrader.orgE<gt> |
| 208 |
weasel |
54 |
|
| 209 |
|
|
=head1 BUGS |
| 210 |
|
|
|
| 211 |
weasel |
103 |
Please report them at E<lt>URL:http://savannah.gnu.org/bugs/?group=echolotE<gt> |
| 212 |
weasel |
54 |
|
| 213 |
|
|
=cut |
| 214 |
|
|
|
| 215 |
weasel |
1 |
use strict; |
| 216 |
|
|
use Getopt::Long; |
| 217 |
weasel |
54 |
use English; |
| 218 |
weasel |
91 |
use Carp; |
| 219 |
weasel |
34 |
use lib qw{ . lib }; |
| 220 |
weasel |
1 |
use Echolot::Config; |
| 221 |
|
|
use Echolot::Globals; |
| 222 |
|
|
use Echolot::Storage::File; |
| 223 |
weasel |
15 |
use Echolot::Scheduler; |
| 224 |
weasel |
1 |
use Echolot::Conf; |
| 225 |
|
|
use Echolot::Mailin; |
| 226 |
weasel |
15 |
use Echolot::Pinger; |
| 227 |
weasel |
34 |
use Echolot::Stats; |
| 228 |
weasel |
54 |
use Echolot::Commands; |
| 229 |
weasel |
106 |
use Echolot::Thesaurus; |
| 230 |
weasel |
1 |
|
| 231 |
|
|
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; |
| 232 |
|
|
|
| 233 |
weasel |
54 |
|
| 234 |
weasel |
161 |
my $VERSION = '2.0beta12'; |
| 235 |
weasel |
117 |
|
| 236 |
|
|
|
| 237 |
weasel |
88 |
my $redirected_stdio = 0; |
| 238 |
weasel |
54 |
|
| 239 |
|
|
sub setSigHandlers() { |
| 240 |
|
|
$SIG{'HUP'} = sub { |
| 241 |
weasel |
115 |
print "Got SIGHUP. scheduling readcommands\n"; |
| 242 |
weasel |
94 |
Echolot::Globals::get()->{'scheduler'}->schedule('readcommands', time() ); |
| 243 |
weasel |
88 |
if ($redirected_stdio) { |
| 244 |
|
|
close STDOUT; |
| 245 |
|
|
close STDERR; |
| 246 |
|
|
open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n"); |
| 247 |
|
|
open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n"); |
| 248 |
|
|
}; |
| 249 |
weasel |
54 |
}; |
| 250 |
|
|
$SIG{'INT'} = sub { |
| 251 |
|
|
print "Got SIGINT. scheduling exit\n"; |
| 252 |
weasel |
94 |
Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() ); |
| 253 |
weasel |
54 |
}; |
| 254 |
|
|
$SIG{'QUIT'} = sub { |
| 255 |
|
|
print "Got SIGQUIT. scheduling exit\n"; |
| 256 |
weasel |
94 |
Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() ); |
| 257 |
weasel |
54 |
}; |
| 258 |
|
|
$SIG{'TERM'} = sub { |
| 259 |
|
|
print "Got SIGTERM. scheduling exit\n"; |
| 260 |
weasel |
94 |
Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() ); |
| 261 |
weasel |
54 |
}; |
| 262 |
weasel |
34 |
}; |
| 263 |
weasel |
54 |
|
| 264 |
weasel |
88 |
|
| 265 |
|
|
|
| 266 |
weasel |
54 |
sub commit_prospective_address() { |
| 267 |
|
|
Echolot::Globals::get()->{'storage'}->commit_prospective_address(); |
| 268 |
weasel |
34 |
}; |
| 269 |
weasel |
60 |
sub expire() { |
| 270 |
|
|
Echolot::Globals::get()->{'storage'}->expire(); |
| 271 |
|
|
}; |
| 272 |
weasel |
54 |
|
| 273 |
|
|
|
| 274 |
|
|
|
| 275 |
|
|
|
| 276 |
|
|
|
| 277 |
weasel |
94 |
sub command_adddelete(@) { |
| 278 |
|
|
my $command = shift @_; |
| 279 |
weasel |
88 |
my @argv = @_; |
| 280 |
weasel |
54 |
|
| 281 |
weasel |
94 |
die ("command_adddelete requires command\n") unless defined $command; |
| 282 |
weasel |
88 |
die ("add requires argument <address>\n") unless scalar @argv; |
| 283 |
weasel |
75 |
my @addresses; |
| 284 |
weasel |
88 |
for my $address (@argv) { |
| 285 |
weasel |
75 |
die ("argument <address> is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ ); |
| 286 |
|
|
push @addresses, $address; |
| 287 |
|
|
}; |
| 288 |
|
|
for my $address (@addresses) { |
| 289 |
weasel |
94 |
Echolot::Commands::addCommand("$command $address"); |
| 290 |
weasel |
75 |
}; |
| 291 |
weasel |
88 |
}; |
| 292 |
|
|
|
| 293 |
|
|
sub command_set(@) { |
| 294 |
|
|
my @argv = @_; |
| 295 |
|
|
|
| 296 |
weasel |
75 |
my @settings; |
| 297 |
weasel |
88 |
while (scalar @argv && $argv[0] =~ /^(showit|pingit|fetch)=(on|off)$/) { |
| 298 |
|
|
push @settings, $argv[0]; |
| 299 |
|
|
shift @argv; |
| 300 |
weasel |
75 |
}; |
| 301 |
|
|
|
| 302 |
|
|
my @addresses; |
| 303 |
weasel |
88 |
for my $address (@argv) { |
| 304 |
weasel |
75 |
die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ ); |
| 305 |
|
|
push @addresses, $address; |
| 306 |
|
|
}; |
| 307 |
|
|
|
| 308 |
weasel |
88 |
for my $address (@argv) { |
| 309 |
weasel |
75 |
for my $setting (@settings) { |
| 310 |
|
|
Echolot::Commands::addCommand("set $address $setting"); |
| 311 |
|
|
}; |
| 312 |
|
|
}; |
| 313 |
weasel |
88 |
}; |
| 314 |
|
|
|
| 315 |
weasel |
103 |
sub command_setremailercaps(@) { |
| 316 |
|
|
my @argv = @_; |
| 317 |
weasel |
94 |
|
| 318 |
weasel |
103 |
my @caps; |
| 319 |
|
|
for my $caps (@argv) { |
| 320 |
|
|
my ($remailer_nick, $remailer_address) = ($caps =~ /^\s* \$remailer{"(.*)"} \s*=\s* "<(.*@.*)>.*"; \s*$/ix); |
| 321 |
|
|
die ("caps '$caps' is not a valid remailer caps line\n") unless (defined $remailer_nick && defined $remailer_address); |
| 322 |
|
|
push @caps, { |
| 323 |
|
|
address => $remailer_address, |
| 324 |
|
|
caps => $caps }; |
| 325 |
|
|
}; |
| 326 |
|
|
for my $caps (@caps) { |
| 327 |
|
|
Echolot::Commands::addCommand("setremailercaps ".$caps->{'address'}." ".$caps->{'caps'}); |
| 328 |
|
|
}; |
| 329 |
|
|
}; |
| 330 |
weasel |
94 |
|
| 331 |
weasel |
103 |
sub command_deleteremailercaps(@) { |
| 332 |
|
|
my @argv = @_; |
| 333 |
|
|
|
| 334 |
|
|
my @addresses; |
| 335 |
|
|
for my $address (@argv) { |
| 336 |
|
|
die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ ); |
| 337 |
|
|
push @addresses, $address; |
| 338 |
|
|
}; |
| 339 |
|
|
|
| 340 |
|
|
for my $address (@argv) { |
| 341 |
|
|
Echolot::Commands::addCommand("deleteremailercaps $address"); |
| 342 |
|
|
}; |
| 343 |
|
|
}; |
| 344 |
|
|
|
| 345 |
|
|
|
| 346 |
weasel |
88 |
sub pid_exists() { |
| 347 |
|
|
return (-e Echolot::Config::get()->{'pidfile'}); |
| 348 |
|
|
}; |
| 349 |
|
|
|
| 350 |
weasel |
129 |
sub daemon_run($) { |
| 351 |
|
|
my ($process) = @_; |
| 352 |
|
|
|
| 353 |
weasel |
88 |
die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n") |
| 354 |
|
|
if pid_exists(); |
| 355 |
|
|
open (PIDFILE, '>'.Echolot::Config::get()->{'pidfile'}) or |
| 356 |
weasel |
152 |
confess ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n"); |
| 357 |
weasel |
88 |
print PIDFILE "$PROCESS_ID ".Echolot::Globals::get()->{'hostname'}." ".time()."\n"; |
| 358 |
|
|
close PIDFILE; |
| 359 |
|
|
|
| 360 |
weasel |
60 |
Echolot::Globals::initStorage(); |
| 361 |
weasel |
54 |
setSigHandlers(); |
| 362 |
weasel |
1 |
|
| 363 |
weasel |
94 |
Echolot::Globals::get()->{'scheduler'} = new Echolot::Scheduler; |
| 364 |
|
|
my $scheduler = Echolot::Globals::get()->{'scheduler'}; |
| 365 |
weasel |
83 |
$scheduler->add('exit' , -1 , 0, 'exit' ); |
| 366 |
|
|
$scheduler->add('readcommands' , -1 , 0, \&Echolot::Commands::processCommands ); |
| 367 |
weasel |
1 |
|
| 368 |
weasel |
83 |
$scheduler->add('processmail' , Echolot::Config::get()->{'processmail'} , 0, \&Echolot::Mailin::process ); |
| 369 |
|
|
$scheduler->add('ping' , Echolot::Config::get()->{'pinger_interval'} , 0, \&Echolot::Pinger::send_pings ); |
| 370 |
weasel |
107 |
$scheduler->add('buildstats' , Echolot::Config::get()->{'buildstats'} , 0, \&Echolot::Stats::build_stats ); |
| 371 |
|
|
$scheduler->add('buildkeys' , Echolot::Config::get()->{'buildkeys'} , 0, \&Echolot::Stats::build_keys ); |
| 372 |
weasel |
106 |
$scheduler->add('buildthesaurus' , Echolot::Config::get()->{'build_thesaurus'} , 0, \&Echolot::Thesaurus::build_thesaurus ); |
| 373 |
weasel |
54 |
|
| 374 |
weasel |
83 |
$scheduler->add('commitprospectives' , Echolot::Config::get()->{'commitprospectives'} , 0, \&commit_prospective_address ); |
| 375 |
|
|
$scheduler->add('expire' , Echolot::Config::get()->{'expire'} , 0, \&expire ); |
| 376 |
|
|
$scheduler->add('getkeyconf' , Echolot::Config::get()->{'getkeyconf'} , 0, \&Echolot::Conf::send_requests ); |
| 377 |
weasel |
121 |
$scheduler->add('check_resurrection' , Echolot::Config::get()->{'check_resurrection'} , 0, \&Echolot::Conf::check_resurrection ); |
| 378 |
weasel |
54 |
|
| 379 |
weasel |
127 |
Echolot::Globals::get()->{'scheduler'}->schedule('readcommands', time() ) |
| 380 |
weasel |
129 |
if ($process); |
| 381 |
weasel |
127 |
|
| 382 |
weasel |
54 |
$scheduler->run(); |
| 383 |
|
|
|
| 384 |
|
|
Echolot::Globals::get()->{'storage'}->commit(); |
| 385 |
|
|
Echolot::Globals::get()->{'storage'}->finish(); |
| 386 |
weasel |
88 |
|
| 387 |
|
|
unlink (Echolot::Config::get()->{'pidfile'}) or |
| 388 |
|
|
cluck ("Cannot unlink pidfile ".Echolot::Config::get()->{'pidfile'}); |
| 389 |
|
|
}; |
| 390 |
|
|
|
| 391 |
|
|
sub send_sig($) { |
| 392 |
|
|
my ($sig) = @_; |
| 393 |
|
|
|
| 394 |
weasel |
107 |
die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' does not exist\n") |
| 395 |
weasel |
88 |
unless pid_exists(); |
| 396 |
|
|
open (PIDFILE, '<'.Echolot::Config::get()->{'pidfile'}) or |
| 397 |
weasel |
152 |
confess ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n"); |
| 398 |
weasel |
88 |
my $line = <PIDFILE>; |
| 399 |
|
|
close PIDFILE; |
| 400 |
|
|
|
| 401 |
|
|
my ($pid, $host, $time) = $line =~ /^(\d+) \s+ (\S+) \s+ (\d+) \s* $/x or |
| 402 |
weasel |
152 |
confess ("Cannot parse pidfile '$line'\n"); |
| 403 |
weasel |
88 |
my $sent = kill $sig, $pid; |
| 404 |
|
|
($sent == 1) or |
| 405 |
weasel |
152 |
confess ("Did not send signal $sig to exactly one process but $sent. (pidfile reads $line)\n"); |
| 406 |
weasel |
88 |
}; |
| 407 |
|
|
|
| 408 |
|
|
sub daemon_hup() { |
| 409 |
|
|
send_sig(1); |
| 410 |
|
|
}; |
| 411 |
|
|
|
| 412 |
|
|
sub daemon_stop() { |
| 413 |
|
|
send_sig(15); |
| 414 |
|
|
}; |
| 415 |
|
|
|
| 416 |
weasel |
91 |
sub make_dirs() { |
| 417 |
|
|
for my $dir ( |
| 418 |
|
|
Echolot::Config::get()->{'resultdir'}, |
| 419 |
weasel |
106 |
Echolot::Config::get()->{'thesaurusdir'}, |
| 420 |
weasel |
91 |
Echolot::Config::get()->{'private_resultdir'}, |
| 421 |
|
|
Echolot::Config::get()->{'gnupghome'}, |
| 422 |
|
|
Echolot::Config::get()->{'tmpdir'}, |
| 423 |
|
|
Echolot::Config::get()->{'storage'}->{'File'}->{'basedir'} |
| 424 |
|
|
) { |
| 425 |
|
|
if ( ! -d $dir ) { |
| 426 |
|
|
mkdir ($dir) or |
| 427 |
weasel |
152 |
confess ("Cannot create directory $dir: $!\n"); |
| 428 |
weasel |
91 |
}; |
| 429 |
|
|
}; |
| 430 |
|
|
for my $dir ( |
| 431 |
|
|
Echolot::Config::get()->{'mailindir'}, |
| 432 |
|
|
Echolot::Config::get()->{'mailindir'}.'/cur', |
| 433 |
|
|
Echolot::Config::get()->{'mailindir'}.'/tmp', |
| 434 |
|
|
Echolot::Config::get()->{'mailindir'}.'/new', |
| 435 |
|
|
Echolot::Config::get()->{'mailerrordir'}, |
| 436 |
|
|
Echolot::Config::get()->{'mailerrordir'}.'/cur', |
| 437 |
|
|
Echolot::Config::get()->{'mailerrordir'}.'/tmp', |
| 438 |
|
|
Echolot::Config::get()->{'mailerrordir'}.'/new' |
| 439 |
|
|
) { |
| 440 |
|
|
if ( ! -d $dir ) { |
| 441 |
|
|
mkdir ($dir, 0700) or |
| 442 |
weasel |
152 |
confess ("Cannot create directory $dir: $!\n"); |
| 443 |
weasel |
91 |
}; |
| 444 |
|
|
}; |
| 445 |
|
|
}; |
| 446 |
weasel |
88 |
|
| 447 |
weasel |
91 |
|
| 448 |
|
|
|
| 449 |
|
|
|
| 450 |
|
|
|
| 451 |
|
|
|
| 452 |
|
|
|
| 453 |
|
|
|
| 454 |
|
|
|
| 455 |
|
|
|
| 456 |
|
|
|
| 457 |
|
|
|
| 458 |
weasel |
88 |
my $params; |
| 459 |
|
|
Getopt::Long::config('bundling'); |
| 460 |
|
|
if (!GetOptions ( |
| 461 |
|
|
'help' => \$params->{'help'}, |
| 462 |
weasel |
117 |
'version' => \$params->{'version'}, |
| 463 |
weasel |
88 |
'verbose' => \$params->{'verbose'}, |
| 464 |
weasel |
94 |
'nohup' => \$params->{'nohup'}, |
| 465 |
weasel |
88 |
'detach' => \$params->{'detach'}, |
| 466 |
weasel |
127 |
'process' => \$params->{'process'}, |
| 467 |
weasel |
88 |
)) { |
| 468 |
|
|
die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n"); |
| 469 |
|
|
}; |
| 470 |
|
|
if ($params->{'help'}) { |
| 471 |
weasel |
115 |
print ("Usage: $PROGRAM_NAME [options] command\n"); |
| 472 |
|
|
print ("See man pingd or perldoc pingd for more info.\n"); |
| 473 |
weasel |
117 |
print ("echolot $VERSION - (c) 2002 Peter Palfrader <peter\@palfrader.org>\n"); |
| 474 |
|
|
print ("http://savannah.gnu.org/projects/echolot/\n"); |
| 475 |
weasel |
88 |
exit 0; |
| 476 |
|
|
}; |
| 477 |
weasel |
117 |
if ($params->{'version'}) { |
| 478 |
|
|
print ("echolot $VERSION\n"); |
| 479 |
|
|
print ("(c) 2002 Peter Palfrader <peter\@palfrader.org>\n"); |
| 480 |
|
|
print ("http://savannah.gnu.org/projects/echolot/\n"); |
| 481 |
|
|
exit 0; |
| 482 |
|
|
}; |
| 483 |
weasel |
88 |
|
| 484 |
|
|
my $COMMAND = shift @ARGV; |
| 485 |
|
|
die ("command required\n") unless defined $COMMAND; |
| 486 |
|
|
|
| 487 |
|
|
|
| 488 |
|
|
Echolot::Config::init( $params ); |
| 489 |
|
|
chdir( Echolot::Config::get()->{'homedir'} ); |
| 490 |
|
|
Echolot::Globals::init(); |
| 491 |
|
|
|
| 492 |
|
|
|
| 493 |
weasel |
94 |
if ($COMMAND eq 'add' || $COMMAND eq 'delete') { |
| 494 |
|
|
command_adddelete($COMMAND, @ARGV); |
| 495 |
|
|
if (!$params->{'nohup'} && pid_exists()) { |
| 496 |
weasel |
88 |
daemon_hup() |
| 497 |
|
|
} else { |
| 498 |
weasel |
125 |
print "Don't forget to run $PROGRAM_NAME process.\n"; |
| 499 |
weasel |
88 |
}; |
| 500 |
|
|
} elsif ($COMMAND eq 'set') { |
| 501 |
|
|
command_set(@ARGV); |
| 502 |
weasel |
94 |
if (!$params->{'nohup'} && pid_exists()) { |
| 503 |
weasel |
88 |
daemon_hup() |
| 504 |
|
|
} else { |
| 505 |
weasel |
125 |
print "Don't forget to run $PROGRAM_NAME process.\n"; |
| 506 |
weasel |
88 |
}; |
| 507 |
weasel |
103 |
} elsif ($COMMAND eq 'setremailercaps') { |
| 508 |
|
|
command_setremailercaps(@ARGV); |
| 509 |
|
|
if (!$params->{'nohup'} && pid_exists()) { |
| 510 |
|
|
daemon_hup() |
| 511 |
|
|
} else { |
| 512 |
weasel |
125 |
print "Don't forget to run $PROGRAM_NAME process.\n"; |
| 513 |
weasel |
103 |
}; |
| 514 |
|
|
} elsif ($COMMAND eq 'deleteremailercaps') { |
| 515 |
|
|
command_deleteremailercaps(@ARGV); |
| 516 |
|
|
if (!$params->{'nohup'} && pid_exists()) { |
| 517 |
|
|
daemon_hup() |
| 518 |
|
|
} else { |
| 519 |
weasel |
125 |
print "Don't forget to run $PROGRAM_NAME process.\n"; |
| 520 |
weasel |
103 |
}; |
| 521 |
weasel |
94 |
} elsif ($COMMAND eq 'getkeyconf') { |
| 522 |
|
|
Echolot::Commands::addCommand("getkeyconf"); |
| 523 |
|
|
if (!$params->{'nohup'} && pid_exists()) { |
| 524 |
|
|
daemon_hup() |
| 525 |
|
|
} else { |
| 526 |
weasel |
125 |
print "Don't forget to run $PROGRAM_NAME process.\n"; |
| 527 |
weasel |
94 |
}; |
| 528 |
weasel |
88 |
} elsif ($COMMAND eq 'process') { |
| 529 |
|
|
daemon_hup(); |
| 530 |
|
|
} elsif ($COMMAND eq 'stop') { |
| 531 |
|
|
daemon_stop(); |
| 532 |
|
|
} elsif ($COMMAND eq 'start') { |
| 533 |
weasel |
103 |
die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n") |
| 534 |
|
|
if pid_exists(); |
| 535 |
weasel |
91 |
make_dirs(); |
| 536 |
weasel |
88 |
if ($params->{'detach'}) { |
| 537 |
|
|
print "Detaching.\n"; |
| 538 |
|
|
unless (fork()) { |
| 539 |
|
|
close STDOUT; |
| 540 |
|
|
close STDERR; |
| 541 |
|
|
open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n"); |
| 542 |
|
|
open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n"); |
| 543 |
|
|
close STDIN; |
| 544 |
|
|
$redirected_stdio = 1; |
| 545 |
weasel |
105 |
print "Startup at ".scalar localtime().".\n"; |
| 546 |
weasel |
129 |
daemon_run( $params->{'process'} ); |
| 547 |
weasel |
105 |
print "done at ".scalar localtime().".\n"; |
| 548 |
weasel |
88 |
}; |
| 549 |
|
|
} else { |
| 550 |
weasel |
129 |
daemon_run( $params->{'process'} ); |
| 551 |
weasel |
88 |
}; |
| 552 |
weasel |
81 |
} elsif ($COMMAND eq 'dumpconf') { |
| 553 |
|
|
Echolot::Config::dump(); |
| 554 |
weasel |
75 |
} elsif ($COMMAND eq 'convert') { |
| 555 |
|
|
Echolot::Globals::initStorage(); |
| 556 |
|
|
setSigHandlers(); |
| 557 |
|
|
|
| 558 |
|
|
Echolot::Globals::get()->{'storage'}->convert(); |
| 559 |
|
|
|
| 560 |
|
|
Echolot::Globals::get()->{'storage'}->commit(); |
| 561 |
|
|
Echolot::Globals::get()->{'storage'}->finish(); |
| 562 |
weasel |
54 |
} else { |
| 563 |
|
|
die ("Command $COMMAND unknown"); |
| 564 |
|
|
}; |
| 565 |
|
|
|
| 566 |
weasel |
34 |
exit 0; |
| 567 |
weasel |
1 |
|
| 568 |
|
|
# vim: set ts=4 shiftwidth=4: |