1 # Copyright (C) 2009 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
20 from __future__
import absolute_import
, unicode_literals
36 from zope
.interface
import implements
38 from mailman
.config
import config
39 from mailman
.i18n
import _
40 from mailman
.interfaces
.command
import ICLISubCommand
43 qlog
= logging
.getLogger('mailman.qrunner')
48 """Start the Mailman daemons."""
50 implements(ICLISubCommand
)
54 def add(self
, parser
, command_parser
):
55 """See `ICLISubCommand`."""
56 command_parser
.add_argument(
58 default
=False, action
='store_true',
60 If the master watcher finds an existing master lock, it will
61 normally exit with an error message. With this option,the master
62 will perform an extra level of checking. If a process matching
63 the host/pid described in the lock file is running, the master
64 will still exit, requiring you to manually clean up the lock. But
65 if no matching process is found, the master will remove the
66 apparently stale lock and make another attempt to claim the master
68 command_parser
.add_argument(
69 '-u', '--run-as-user',
70 default
=True, action
='store_false',
72 Normally, this script will refuse to run if the user id and group
73 id are not set to the 'mailman' user and group (as defined when
74 you configured Mailman). If run as root, this script will change
75 to this user and group before the check is made.
77 This can be inconvenient for testing and debugging purposes, so
78 the -u flag means that the step that sets and checks the uid/gid
79 is skipped, and the program is run as the current user and group.
80 This flag is not recommended for normal production environments.
82 Note though, that if you run with -u and are not in the mailman
83 group, you may have permission problems, such as begin unable to
84 delete a list's archives through the web. Tough luck!"""))
85 command_parser
.add_argument(
87 default
=False, action
='store_true',
89 Don't print status messages. Error messages are still printed to
92 def process(self
, args
):
93 """See `ICLISubCommand`."""
97 # Daemon process startup according to Stevens, Advanced Programming in
98 # the UNIX Environment, Chapter 13.
102 log(_("Starting Mailman's master qrunner"))
104 # child: Create a new session and become the session leader, but since
105 # we won't be opening any terminal devices, don't do the
106 # ultra-paranoid suggestion of doing a second fork after the setsid()
109 # Instead of cd'ing to root, cd to the Mailman runtime directory.
110 os
.chdir(config
.VAR_DIR
)
111 # Exec the master watcher.
113 sys
.executable
, sys
.executable
,
114 os
.path
.join(config
.BIN_DIR
, 'master'),
117 execl_args
.append('--force')
119 execl_args
.extend(['-C', args
.config
])
120 qlog
.debug('starting: %s', execl_args
)
121 os
.execl(*execl_args
)
122 # We should never get here.
123 raise RuntimeError('os.execl() failed')
127 def kill_watcher(sig
):
129 with
open(config
.PIDFILE
) as fp
:
130 pid
= int(fp
.read().strip())
131 except (IOError, ValueError) as error
:
132 # For i18n convenience
133 print >> sys
.stderr
, _('PID unreadable in: $config.PIDFILE')
134 print >> sys
.stderr
, error
135 print >> sys
.stderr
, _('Is qrunner even running?')
139 except OSError as error
:
140 if e
.errno
!= errno
.ESRCH
:
142 print >> sys
.stderr
, _('No child with pid: $pid')
143 print >> sys
.stderr
, e
144 print >> sys
.stderr
, _('Stale pid file removed.')
145 os
.unlink(config
.PIDFILE
)
150 """Common base class for simple, signal sending commands."""
152 implements(ICLISubCommand
)
158 def add(self
, parser
, command_parser
):
159 """See `ICLISubCommand`."""
160 command_parser
.add_argument(
162 default
=False, action
='store_true',
164 Don't print status messages. Error messages are still printed to
167 def process(self
, args
):
168 """See `ICLISubCommand`."""
170 print _(self
.message
)
171 kill_watcher(self
.signal
)
174 class Stop(SignalCommand
):
175 """Stop the Malman daemons."""
178 message
= _("Shutting down Mailman's master qrunner")
179 signal
= signal
.SIGTERM
182 class Reopen(SignalCommand
):
183 """Reopen the Mailman daemons."""
186 message
= _('Reopening the Mailman qrunners')
187 signal
= signal
.SIGHUP
190 class Restart(SignalCommand
):
191 """Stop the Mailman daemons."""
193 implements(ICLISubCommand
)
196 message
= _('Restarting the Mailman qrunners')
197 signal
= signal
.SIGUSR1