Skip to content
Newer
Older
100755 371 lines (321 sloc) 10.3 KB
29ac286 @aqua - Enable taint checking
aqua authored
1 #!/usr/bin/perl -Tw
c408aa9 @abh Update copyright year
authored
2 # Copyright (c) 2001-2010 Ask Bjoern Hansen. See the LICENSE file for details.
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
3 # The "command dispatch" system is taken from colobus - http://trainedmonkey.com/colobus/
4 #
ff0c613 @abh Update URL
authored
5 # For more information see http://smtpd.develooper.com/
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
6 #
7 #
8
9 use lib 'lib';
10 use Qpsmtpd::TcpServer;
11 use Qpsmtpd::Constants;
12 use IO::Socket;
698fc01 Make pid-file optional
Matt Sergeant authored
13 use IO::Select;
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
14 use Socket;
2db4878 Applied patch from issue #5: qpsmtpd-forkserver 0.32 patches
Matt Sergeant authored
15 use Getopt::Long qw(:config no_ignore_case);
f84bd18 Slightly better signal handling - may help stability issues for some …
Matt Sergeant authored
16 use POSIX qw(:sys_wait_h :errno_h :signal_h);
72da879 Ensure that each child process in qpsmtpd-forkserver will use a
Peter J. Holzer authored
17 use Net::DNS::Header;
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
18 use strict;
19 $| = 1;
20
ccf990e IPv6 support from issue #7.
Matt Sergeant authored
21 my $has_ipv6 = Qpsmtpd::TcpServer::has_ipv6;
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
22
23 if ($has_ipv6) {
02bf7b8 @aqua Fix startup of qpsmtpd-forkserver on hosts lacking Socket6 (it's not …
aqua authored
24 eval 'use Socket6';
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
25 }
26
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
27 # Configuration
1e68345 @aqua Clean up whitespace (mainloop had a swath of 4-space indentation, whi…
aqua authored
28 my $MAXCONN = 15; # max simultaneous connections
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
29 my @PORT; # port number(s)
1e68345 @aqua Clean up whitespace (mainloop had a swath of 4-space indentation, whi…
aqua authored
30 my @LOCALADDR; # ip address(es) to bind to
31 my $MAXCONNIP = 5; # max simultaneous connections from one IP
698fc01 Make pid-file optional
Matt Sergeant authored
32 my $PID_FILE = '';
a2064bc @aqua Add --detach commandline option to forkserver; if supplied, daemonize…
aqua authored
33 my $DETACH; # daemonize on startup
2db4878 Applied patch from issue #5: qpsmtpd-forkserver 0.32 patches
Matt Sergeant authored
34 my $NORDNS;
35
36 my $USER = (getpwuid $>)[0]; # user to suid to
37 $USER = "smtpd" if $USER eq "root";
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
38
29ac286 @aqua - Enable taint checking
aqua authored
39 sub usage {
40 print <<"EOT";
41 usage: qpsmtpd-forkserver [ options ]
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
42 -l, --listen-address addr : listen on specific address(es); can be specified
ccf990e IPv6 support from issue #7.
Matt Sergeant authored
43 multiple times for multiple bindings. IPv6
44 addresses must be inside square brackets [], and
45 don't need to be zero padded.
46 Default is [::] (if has_ipv6) or 0.0.0.0 (if not)
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
47 -p, --port P : listen on a specific port; default 2525; can be
48 specified multiple times for multiple bindings.
29ac286 @aqua - Enable taint checking
aqua authored
49 -c, --limit-connections N : limit concurrent connections to N; default 15
b8958d3 @aqua forkserver: accurately report default run-as user
aqua authored
50 -u, --user U : run as a particular user (default '$USER')
22a1d99 @rspier From: Jim Winstead
rspier authored
51 -m, --max-from-ip M : limit connections from a single IP; default 5
03f8c0d @abh
authored
52 --pid-file P : print main servers PID to file P
a2064bc @aqua Add --detach commandline option to forkserver; if supplied, daemonize…
aqua authored
53 -d, --detach : detach from controlling terminal (daemonize)
2db4878 Applied patch from issue #5: qpsmtpd-forkserver 0.32 patches
Matt Sergeant authored
54 -H, --no-rdns : don't perform reverse DNS lookups
29ac286 @aqua - Enable taint checking
aqua authored
55 EOT
56 exit 0;
57 }
58
59 GetOptions('h|help' => \&usage,
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
60 'l|listen-address=s' => \@LOCALADDR,
29ac286 @aqua - Enable taint checking
aqua authored
61 'c|limit-connections=i' => \$MAXCONN,
22a1d99 @rspier From: Jim Winstead
rspier authored
62 'm|max-from-ip=i' => \$MAXCONNIP,
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
63 'p|port=s' => \@PORT,
03f8c0d @abh
authored
64 'u|user=s' => \$USER,
698fc01 Make pid-file optional
Matt Sergeant authored
65 'pid-file=s' => \$PID_FILE,
a2064bc @aqua Add --detach commandline option to forkserver; if supplied, daemonize…
aqua authored
66 'd|detach' => \$DETACH,
2db4878 Applied patch from issue #5: qpsmtpd-forkserver 0.32 patches
Matt Sergeant authored
67 'H|no-rdns' => \$NORDNS,
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
68 ) || &usage;
29ac286 @aqua - Enable taint checking
aqua authored
69
70 # detaint the commandline
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
71 if ($has_ipv6) {
72 @LOCALADDR = ( '[::]' ) if !@LOCALADDR;
73 }
74 else {
75 @LOCALADDR = ( '0.0.0.0' ) if !@LOCALADDR;
76 }
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
77 @PORT = ( 2525 ) if !@PORT;
78
79 my @LISTENADDR;
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
80 for (0..$#LOCALADDR) {
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
81 if ($LOCALADDR[$_] =~ /^(\[.*\]|[\d\w\-.]+)(?::(\d+))?$/) {
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
82 if ( defined $2 ) {
83 push @LISTENADDR, { 'addr' => $1, 'port' => $2 };
84 } else {
85 my $addr = $1;
86 for (0..$#PORT) {
87 if ( $PORT[$_] =~ /^(\d+)$/ ) {
88 push @LISTENADDR, { 'addr' => $addr, 'port' => $1 };
89 } else {
90 &usage;
91 }
92 }
93 }
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
94 } else {
95 &usage;
96 }
97 }
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
98
29ac286 @aqua - Enable taint checking
aqua authored
99 if ($USER =~ /^([\w\-]+)$/) { $USER = $1 } else { &usage }
100 if ($MAXCONN =~ /^(\d+)$/) { $MAXCONN = $1 } else { &usage }
101
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
102 delete $ENV{ENV};
103 $ENV{PATH} = '/bin:/usr/bin:/var/qmail/bin';
104
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
105 my %childstatus = ();
106
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
107 sub REAPER {
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
108 while ( defined(my $chld = waitpid(-1, WNOHANG)) ){
109 last unless $chld > 0;
e331f6b Add plugable logging support include sample plugin which replicates the
John Peacock authored
110 ::log(LOGINFO,"cleaning up after $chld");
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
111 delete $childstatus{$chld};
112 }
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
113 }
114
5d40964 Make signal handling slightly more stable
Matt Sergeant authored
115 sub HUNTSMAN {
116 $SIG{CHLD} = 'DEFAULT';
117 kill 'INT' => keys %childstatus;
00e06cc @aqua Remove PID file on exit, if we were told to create one with --pid-file
aqua authored
118 if ($PID_FILE && -e $PID_FILE) {
a4e4c52 @aqua Fix whitespace (spaces for a tab)
aqua authored
119 unlink $PID_FILE or ::log(LOGERROR, "unlink: $PID_FILE: $!");
00e06cc @aqua Remove PID file on exit, if we were told to create one with --pid-file
aqua authored
120 }
5d40964 Make signal handling slightly more stable
Matt Sergeant authored
121 exit(0);
122 }
123
124 $SIG{INT} = \&HUNTSMAN;
125 $SIG{TERM} = \&HUNTSMAN;
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
126
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
127 my $select = new IO::Select;
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
128 my $server;
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
129
130 # establish SERVER socket(s), bind and listen.
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
131 for my $listen_addr (@LISTENADDR) {
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
132 my @Socket_opts = (LocalPort => $listen_addr->{'port'},
2c683f2 Implement multiple IP:PORT listen in forkserver (Devin Carraway).
John Peacock authored
133 LocalAddr => $listen_addr->{'addr'},
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
134 Proto => 'tcp',
135 Reuse => 1,
136 Blocking => 0,
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
137 Listen => SOMAXCONN);
138 if ($has_ipv6) {
139 $server = IO::Socket::INET6->new(@Socket_opts)
140 or die "Creating TCP socket $listen_addr->{'addr'}:$listen_addr->{'port'}: $!\n";
141 }
142 else {
143 $server = IO::Socket::INET->new(@Socket_opts)
144 or die "Creating TCP socket $listen_addr->{'addr'}:$listen_addr->{'port'}: $!\n";
145 }
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
146 IO::Handle::blocking($server, 0);
147 $select->add($server);
148 }
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
149
698fc01 Make pid-file optional
Matt Sergeant authored
150 if ($PID_FILE) {
151 if ($PID_FILE =~ m#^(/[\w\d/\-.]+)$#) { $PID_FILE = $1 } else { &usage }
152 if (-e $PID_FILE) {
153 open PID, "+<$PID_FILE"
154 or die "open pid_file: $!\n";
da5c0a7 @aqua Fix unitialized-value warning if the PID file existed but was zero-le…
aqua authored
155 my $running_pid = <PID> || ''; chomp $running_pid;
698fc01 Make pid-file optional
Matt Sergeant authored
156 if ($running_pid =~ /(\d+)/) {
157 $running_pid = $1;
158 if (kill 0, $running_pid) {
159 die "Found an already running qpsmtpd with pid $running_pid.\n";
160 }
03f8c0d @abh
authored
161 }
698fc01 Make pid-file optional
Matt Sergeant authored
162 seek PID, 0, 0
163 or die "Could not seek back to beginning of $PID_FILE: $!\n";
a3ff03f @aqua Merge r493 from trunk to truncate PID file before re-use
aqua authored
164 truncate PID, 0
165 or die "Could not truncate $PID_FILE at 0: $!";
698fc01 Make pid-file optional
Matt Sergeant authored
166 } else {
167 open PID, ">$PID_FILE"
168 or die "open pid_file: $!\n";
03f8c0d @abh
authored
169 }
170 }
698fc01 Make pid-file optional
Matt Sergeant authored
171
172 # Load plugins here
173 my $qpsmtpd = Qpsmtpd::TcpServer->new();
03f8c0d @abh
authored
174
175 # Drop privileges
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
176 my (undef, undef, $quid, $qgid) = getpwnam $USER or
177 die "unable to determine uid/gid for $USER\n";
03f8c0d @abh
authored
178 my $groups = "$qgid $qgid";
179 while (my ($name,$passwd,$gid,$members) = getgrent()) {
180 my @m = split(/ /, $members);
181 if (grep {$_ eq $USER} @m) {
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
182 $groups .= " $gid";
03f8c0d @abh
authored
183 }
184 }
2db4878 Applied patch from issue #5: qpsmtpd-forkserver 0.32 patches
Matt Sergeant authored
185 endgrent;
03f8c0d @abh
authored
186 $) = $groups;
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
187 POSIX::setgid($qgid) or
188 die "unable to change gid: $!\n";
189 POSIX::setuid($quid) or
190 die "unable to change uid: $!\n";
191 $> = $quid;
192
239daaf @aqua Drop root privileges before loading plugins, rather than after. This …
aqua authored
193 $qpsmtpd->load_plugins;
194
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
195 foreach my $listen_addr ( @LISTENADDR ) {
196 ::log(LOGINFO,"Listening on $listen_addr->{'addr'}:$listen_addr->{'port'}");
2c683f2 Implement multiple IP:PORT listen in forkserver (Devin Carraway).
John Peacock authored
197 }
e331f6b Add plugable logging support include sample plugin which replicates the
John Peacock authored
198 ::log(LOGINFO, 'Running as user '.
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
199 (getpwuid($>) || $>) .
200 ', group '.
201 (getgrgid($)) || $)));
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
202
a2064bc @aqua Add --detach commandline option to forkserver; if supplied, daemonize…
aqua authored
203 if ($DETACH) {
204 open STDIN, '/dev/null' or die "/dev/null: $!";
205 open STDOUT, '>/dev/null' or die "/dev/null: $!";
206 open STDERR, '>&STDOUT' or die "open(stderr): $!";
207 defined (my $pid = fork) or die "fork: $!";
208 exit 0 if $pid;
209 POSIX::setsid or die "setsid: $!";
210 }
211
212 if ($PID_FILE) {
213 print PID $$,"\n";
214 close PID;
215 }
216
9cbf206 * lib/Qpsmtpd/TcpServer.pm
John Peacock authored
217 # Populate class cached variables
218 $qpsmtpd->spool_dir;
219 $qpsmtpd->size_threshold;
220
a64742c @vetinari prefork, forkserver: restart on SIGHUP: * reset to defaults * clear c…
vetinari authored
221 $SIG{HUP} = sub {
222 $qpsmtpd = Qpsmtpd::TcpServer->new('restart' => 1);
223 $qpsmtpd->load_plugins;
224 $qpsmtpd->spool_dir;
225 $qpsmtpd->size_threshold;
226 };
227
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
228 while (1) {
698fc01 Make pid-file optional
Matt Sergeant authored
229 REAPER();
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
230 my $running = scalar keys %childstatus;
314625d Another small cleanup
Matt Sergeant authored
231 if ($running >= $MAXCONN) {
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
232 ::log(LOGINFO,"Too many connections: $running >= $MAXCONN. Waiting one second.");
4b72a40 Minor cleanup
Matt Sergeant authored
233 sleep(1);
234 next;
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
235 }
1fbfe51 @aqua Implement listening on multiple local addresses simultaneously, if sp…
aqua authored
236 my @ready = $select->can_read(1);
237 next if !@ready;
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
238 while (my $server = shift @ready) {
239 my ($client, $hisaddr) = $server->accept;
240
241 if (!$hisaddr) {
242 # possible something condition...
243 next;
b82536d Support per-IP throttling (Hanno Hecker <hah@uu-x.de>)
Matt Sergeant authored
244 }
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
245 IO::Handle::blocking($client, 1);
ccf990e IPv6 support from issue #7.
Matt Sergeant authored
246 # get local/remote hostname, port and ip address
247 my ($port, $iaddr, $lport, $laddr, $nto_iaddr, $nto_laddr) = Qpsmtpd::TcpServer::lrpip($server, $client, $hisaddr);
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
248
249 my ($rc, @msg) = $qpsmtpd->run_hooks("pre-connection",
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
250 remote_ip => $nto_iaddr,
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
251 remote_port => $port,
6ef0bf2 @abh r4175@embla: ask | 2006-08-28 01:17:10 +0200
authored
252 local_ip => $nto_laddr,
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
253 local_port => $lport,
254 max_conn_ip => $MAXCONNIP,
255 child_addrs => [values %childstatus],
256 );
257 if ($rc == DENYSOFT || $rc == DENYSOFT_DISCONNECT) {
258 unless ($msg[0]) {
259 @msg = ("Sorry, try again later");
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
260 }
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
261 &respond_client($client, 451, @msg);
262 close $client;
263 next;
264 }
265 elsif ($rc == DENY || $rc == DENY_DISCONNECT) {
266 unless ($msg[0]) {
267 @msg = ("Sorry, service not available for you");
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
268 }
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
269 &respond_client($client, 550, @msg);
270 close $client;
271 next;
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
272 }
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
273
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
274 my $pid = safe_fork();
275 if ($pid) {
276 # parent
4a824a2 Improve support for listening to multiple ports and/or multiple IP ad…
John Peacock authored
277 $childstatus{$pid} = $iaddr; # add to table
278 # $childstatus{$pid} = 1; # add to table
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
279 $running++;
280 close($client);
1e68345 @aqua Clean up whitespace (mainloop had a swath of 4-space indentation, whi…
aqua authored
281 next;
f84bd18 Slightly better signal handling - may help stability issues for some …
Matt Sergeant authored
282 }
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
283 # otherwise child
284
285 # all children should have different seeds, to prevent conflicts
72da879 Ensure that each child process in qpsmtpd-forkserver will use a
Peter J. Holzer authored
286 srand();
287 for (0 .. rand(65536)) {
288 Net::DNS::Header::nextid();
289 }
1e68345 @aqua Clean up whitespace (mainloop had a swath of 4-space indentation, whi…
aqua authored
290
2db4878 Applied patch from issue #5: qpsmtpd-forkserver 0.32 patches
Matt Sergeant authored
291 close $_ for $select->handles;
1e68345 @aqua Clean up whitespace (mainloop had a swath of 4-space indentation, whi…
aqua authored
292
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
293 $SIG{$_} = 'DEFAULT' for keys %SIG;
294 $SIG{ALRM} = sub {
295 print $client "421 Connection Timed Out\n";
296 ::log(LOGINFO, "Connection Timed Out");
297 exit; };
1e68345 @aqua Clean up whitespace (mainloop had a swath of 4-space indentation, whi…
aqua authored
298
ccf990e IPv6 support from issue #7.
Matt Sergeant authored
299 # set enviroment variables
300 ($ENV{TCPLOCALIP}, $ENV{TCPREMOTEIP}, $ENV{TCPREMOTEHOST}) = Qpsmtpd::TcpServer::tcpenv($nto_laddr, $nto_iaddr);
301
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
302 # don't do this!
303 #$0 = "qpsmtpd-forkserver: $ENV{TCPREMOTEIP} / $ENV{TCPREMOTEHOST}";
304
305 ::log(LOGINFO, "Accepted connection $running/$MAXCONN from $ENV{TCPREMOTEIP} / $ENV{TCPREMOTEHOST}");
306
307 # dup to STDIN/STDOUT
308 POSIX::dup2(fileno($client), 0);
309 POSIX::dup2(fileno($client), 1);
310
311 $qpsmtpd->start_connection
312 (
313 local_ip => $ENV{TCPLOCALIP},
314 local_port => $lport,
315 remote_ip => $ENV{TCPREMOTEIP},
316 remote_port => $port,
317 );
59b826d Fix to check client is writable before writing to it.
Matt Sergeant authored
318 $qpsmtpd->run($client);
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
319
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
320 $qpsmtpd->run_hooks("post-connection");
ea243c2 @vetinari add reset() to Qpsmtpd::Connection to clear the connection notes after
vetinari authored
321 $qpsmtpd->connection->reset;
eff638d @vetinari forkserver: fix wrong detection of closed connection
vetinari authored
322 close $client;
3fc6a4f Make sure we process all servers after select()
Matt Sergeant authored
323 exit; # child leaves
324 }
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
325 }
326
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
327 sub log {
328 my ($level,$message) = @_;
6620034 * qpsmtpd-forkserver
John Peacock authored
329 $qpsmtpd->log($level,$message);
d8c8d40 @rspier - move configuration to top. (still suboptimal)
rspier authored
330 }
331
c092034 the pre-connection and post-connection hooks are not working in
John Peacock authored
332 sub respond_client {
333 my ($client, $code, @message) = @_;
334 $client->autoflush(1);
335 while (my $msg = shift @message) {
336 my $line = $code . (@message?"-":" ").$msg;
337 ::log(LOGDEBUG, $line);
338 print $client "$line\r\n"
339 or (::log(LOGERROR, "Could not print [$line]: $!"), return 0);
340 }
341 return 1;
342 }
343
698fc01 Make pid-file optional
Matt Sergeant authored
344 ### routine to protect process during fork
345 sub safe_fork {
346
347 ### block signal for fork
348 my $sigset = POSIX::SigSet->new(SIGINT);
349 POSIX::sigprocmask(SIG_BLOCK, $sigset)
350 or die "Can't block SIGINT for fork: [$!]\n";
351
352 ### fork off a child
353 my $pid = fork;
354 unless( defined $pid ){
355 die "Couldn't fork: [$!]\n";
356 }
357
358 ### make SIGINT kill us as it did before
359 $SIG{INT} = 'DEFAULT';
360
361 ### put back to normal
362 POSIX::sigprocmask(SIG_UNBLOCK, $sigset)
363 or die "Can't unblock SIGINT for fork: [$!]\n";
364
365 return $pid;
366 }
367
04dacc4 Pure perl forking qpsmtpd
Matt Sergeant authored
368 __END__
369
370 1;
Something went wrong with that request. Please try again.