]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/contrib/smcontrol.pl
This commit was generated by cvs2svn to compensate for changes in r56545,
[FreeBSD/FreeBSD.git] / contrib / sendmail / contrib / smcontrol.pl
1 #!/usr/local/bin/perl -w
2
3 use FileHandle;
4 use Socket;
5
6 $sendmailDaemon = "/usr/sbin/sendmail -q30m -bd";
7
8 ##########################################################################
9 #
10 #  &get_controlname -- read ControlSocketName option from sendmail.cf
11 #
12 #       Parameters:
13 #               none.
14 #
15 #       Returns:
16 #               control socket filename, undef if not found
17 #
18
19 sub get_controlname
20 {
21         my $cn = undef;
22         my $qd = undef;
23  
24         open(CF, "</etc/sendmail.cf") or return $cn;
25         while (<CF>)
26         {
27                 chomp;
28                 if (/^O ControlSocketName\s*=\s*([^#]+)$/o)
29                 {
30                         $cn = $1;
31                 }
32                 if (/^O QueueDirectory\s*=\s*([^#]+)$/o)
33                 {
34                         $qd = $1;
35                 }
36                 if (/^OQ([^#]+)$/o)
37                 {
38                         $qd = $1;
39                 }
40         }
41         close(CF);
42         if (not defined $cn)
43         {
44                 return undef;
45         }
46         if ($cn !~ /^\//o)
47         {
48                 return undef if (not defined $qd);
49                 
50                 $cn = $qd . "/" . $cn;
51         }
52         return $cn;
53 }
54
55 ##########################################################################
56 #
57 #  &do_command -- send command to sendmail daemon view control socket
58 #
59 #       Parameters:
60 #               controlsocket -- filename for socket
61 #               command -- command to send
62 #
63 #       Returns:
64 #               reply from sendmail daemon
65 #
66
67 sub do_command
68 {
69         my $controlsocket = shift;
70         my $command = shift;
71         my $proto = getprotobyname('ip');
72         my @reply;
73
74         socket(SOCK, PF_UNIX, SOCK_STREAM, $proto) or return undef;
75
76         for ($i = 0; $i < 4; $i++)
77         {
78                 if (!connect(SOCK, sockaddr_un($controlsocket)))
79                 {
80                         if ($i == 3)
81                         {
82                                 close(SOCK);
83                                 return undef;
84                         }
85                         sleep 1;
86                         next;
87                 }
88                 last;
89         }
90         autoflush SOCK 1;
91         print SOCK "$command\n";
92         @reply = <SOCK>;
93         close(SOCK);
94         return join '', @reply;
95 }
96
97 ##########################################################################
98 #
99 #  &sendmail_running -- check if sendmail is running via SMTP
100 #
101 #       Parameters:
102 #               none
103 #
104 #       Returns:
105 #               1 if running, undef otherwise
106 #
107
108 sub sendmail_running
109 {
110         my $port = getservbyname("smtp", "tcp") || 25;
111         my $proto = getprotobyname("tcp");
112         my $iaddr = inet_aton("localhost");
113         my $paddr = sockaddr_in($port, $iaddr);
114
115         socket(SOCK, PF_INET, SOCK_STREAM, $proto) or return undef;
116         if (!connect(SOCK, $paddr))
117         {
118                 close(SOCK);
119                 return undef;
120         }
121         autoflush SOCK 1;
122         while (<SOCK>)
123         {
124                 if (/^(\d{3})([ -])/)
125                 {
126                         if ($1 != 220)
127                         {
128                                 close(SOCK);
129                                 return undef;
130                         }
131                 }
132                 else
133                 {
134                         close(SOCK);
135                         return undef;
136                 }
137                 last if ($2 eq " ");
138         }
139         print SOCK "QUIT\n";
140         while (<SOCK>)
141         {
142                 last if (/^\d{3} /);
143         }
144         close(SOCK);
145         return 1;
146 }
147
148 ##########################################################################
149 #
150 #  &munge_status -- turn machine readable status into human readable text
151 #
152 #       Parameters:
153 #               raw -- raw results from sendmail daemon STATUS query
154 #
155 #       Returns:
156 #               human readable text
157 #
158
159 sub munge_status
160 {
161         my $raw = shift;
162         my $cooked = "";
163         my $daemonStatus = "";
164
165         if ($raw =~ /^(\d+)\/(\d+)$/mg)
166         {
167                 $cooked .= "Current number of children: $1";
168                 if ($2 > 0)
169                 {
170                         $cooked .= " (maximum $2)";
171                 }
172                 $cooked .= "\n";
173         }
174         while ($raw =~ /^(\d+) (.*)$/mg)
175         {
176                 if (not $daemonStatus)
177                 {
178                         $daemonStatus = "(process $1) " . ucfirst($2) . "\n";
179                 }
180                 else
181                 {
182                         $cooked .= "Child Process $1 Status: $2\n";
183                 }
184         }
185         return ($daemonStatus, $cooked);
186 }
187
188 ##########################################################################
189 #
190 #  &start_daemon -- fork off a sendmail daemon
191 #
192 #       Parameters:
193 #               control -- control socket name
194 #
195 #       Returns:
196 #               Error message or "OK" if successful
197 #
198
199 sub start_daemon
200 {
201         my $control = shift;
202         my $pid;
203
204         if ($pid = fork)
205         {
206                 my $exitstat;
207
208                 waitpid $pid, 0 or return "Could not get status of created process: $!\n";
209                 $exitstat = $? / 256;
210                 if ($exitstat != 0)
211                 {
212                         return "sendmail daemon startup exited with exit value $exitstat";
213                 }
214         }
215         elsif (defined $pid)
216         {
217                 exec($main::sendmailDaemon);
218                 die "Unable to start sendmail daemon: $!.\n";
219         }
220         else
221         {
222                 return "Could not create new process: $!\n";
223         }
224         return "OK\n";
225 }
226
227 ##########################################################################
228 #
229 #  &stop_daemon -- stop the sendmail daemon using control socket
230 #
231 #       Parameters:
232 #               control -- control socket name
233 #
234 #       Returns:
235 #               Error message or status message
236 #
237
238 sub stop_daemon
239 {
240         my $control = shift;
241         my $status;
242
243         if (not defined $control)
244         {
245                 return "The control socket is not configured so the daemon can not be stopped.\n";
246         }
247         return &do_command($control, "SHUTDOWN");
248 }
249
250 ##########################################################################
251 #
252 #  &restart_daemon -- restart the sendmail daemon using control socket
253 #
254 #       Parameters:
255 #               control -- control socket name
256 #
257 #       Returns:
258 #               Error message or status message
259 #
260
261 sub restart_daemon
262 {
263         my $control = shift;
264         my $status;
265
266         if (not defined $control)
267         {
268                 return "The control socket is not configured so the daemon can not be restarted.";
269         }
270         return &do_command($control, "RESTART");
271 }
272
273 ##########################################################################
274 #
275 #  &help -- get help from the daemon using the control socket
276 #
277 #       Parameters:
278 #               control -- control socket name
279 #
280 #       Returns:
281 #               Error message or status message
282 #
283
284 sub help
285 {
286         my $control = shift;
287         my $status;
288
289         if (not defined $control)
290         {
291                 return "The control socket is not configured so the daemon can not be queried for help.";
292         }
293         return &do_command($control, "HELP");
294 }
295
296 my $command = shift;
297 my $control = &get_controlname;
298 my $status = undef;
299 my $daemonStatus = undef;
300
301 if (not defined $control)
302 {
303         die "No control socket available.\n";
304 }
305 if (not defined $command)
306 {
307         die "Usage: $0 command\n";
308 }
309 if ($command eq "status")
310 {
311         $status = &do_command($control, "STATUS");
312         if (not defined $status)
313         {
314                 # Not responding on control channel, query via SMTP
315                 if (&sendmail_running)
316                 {
317                         $daemonStatus = "Sendmail is running but not answering status queries.";
318                 }
319                 else
320                 {
321                         $daemonStatus = "Sendmail does not appear to be running.";
322                 }
323         }
324         else
325         {
326                 # Munge control channel output
327                 ($daemonStatus, $status) = &munge_status($status);
328         }
329 }
330 elsif (lc($command) eq "shutdown")
331 {
332         $status = &stop_daemon($control);
333 }
334 elsif (lc($command) eq "restart")
335 {
336         $status = &restart_daemon($control);
337 }
338 elsif (lc($command) eq "start")
339 {
340         $status = &start_daemon($control);
341 }
342 elsif (lc($command) eq "help")
343 {
344         $status = &help($control);
345 }
346 else
347 {
348         die "Unrecognized command $command\n";
349 }
350 if (defined $daemonStatus)
351 {
352         print "Daemon Status: $daemonStatus\n";
353 }
354 if (defined $status)
355 {
356         print "$status\n";
357 }
358 else
359 {
360         die "No response\n";
361 }