source: trunk/third/sendmail/contrib/smcontrol.pl @ 19204

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