1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
# Copyright (C) 2009 by the Free Software Foundation, Inc.
#
# This file is part of GNU Mailman.
#
# GNU Mailman is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
"""Module stuff."""
from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
'Reopen',
'Restart',
'Start',
'Stop',
]
import os
import sys
import signal
import logging
from zope.interface import implements
from mailman.config import config
from mailman.core.i18n import _
from mailman.interfaces.command import ICLISubCommand
qlog = logging.getLogger('mailman.qrunner')
class Start:
"""Start the Mailman daemons."""
implements(ICLISubCommand)
name = 'start'
def add(self, parser, command_parser):
"""See `ICLISubCommand`."""
command_parser.add_argument(
'-f', '--force',
default=False, action='store_true',
help=_("""\
If the master watcher finds an existing master lock, it will
normally exit with an error message. With this option,the master
will perform an extra level of checking. If a process matching
the host/pid described in the lock file is running, the master
will still exit, requiring you to manually clean up the lock. But
if no matching process is found, the master will remove the
apparently stale lock and make another attempt to claim the master
lock."""))
command_parser.add_argument(
'-u', '--run-as-user',
default=True, action='store_false',
help=_("""\
Normally, this script will refuse to run if the user id and group
id are not set to the 'mailman' user and group (as defined when
you configured Mailman). If run as root, this script will change
to this user and group before the check is made.
This can be inconvenient for testing and debugging purposes, so
the -u flag means that the step that sets and checks the uid/gid
is skipped, and the program is run as the current user and group.
This flag is not recommended for normal production environments.
Note though, that if you run with -u and are not in the mailman
group, you may have permission problems, such as begin unable to
delete a list's archives through the web. Tough luck!"""))
command_parser.add_argument(
'-q', '--quiet',
default=False, action='store_true',
help=_("""\
Don't print status messages. Error messages are still printed to
standard error."""))
def process(self, args):
"""See `ICLISubCommand`."""
def log(message):
if not args.quiet:
print message
# Daemon process startup according to Stevens, Advanced Programming in
# the UNIX Environment, Chapter 13.
pid = os.fork()
if pid:
# parent
log(_("Starting Mailman's master qrunner"))
return
# child: Create a new session and become the session leader, but since
# we won't be opening any terminal devices, don't do the
# ultra-paranoid suggestion of doing a second fork after the setsid()
# call.
os.setsid()
# Instead of cd'ing to root, cd to the Mailman runtime directory.
os.chdir(config.VAR_DIR)
# Exec the master watcher.
execl_args = [
sys.executable, sys.executable,
os.path.join(config.BIN_DIR, 'master'),
]
if args.force:
execl_args.append('--force')
if args.config:
execl_args.extend(['-C', args.config])
qlog.debug('starting: %s', execl_args)
os.execl(*execl_args)
# We should never get here.
raise RuntimeError('os.execl() failed')
def kill_watcher(sig):
try:
with open(config.PIDFILE) as fp:
pid = int(fp.read().strip())
except (IOError, ValueError) as error:
# For i18n convenience
print >> sys.stderr, _('PID unreadable in: $config.PIDFILE')
print >> sys.stderr, error
print >> sys.stderr, _('Is qrunner even running?')
return
try:
os.kill(pid, sig)
except OSError as error:
if e.errno != errno.ESRCH:
raise
print >> sys.stderr, _('No child with pid: $pid')
print >> sys.stderr, e
print >> sys.stderr, _('Stale pid file removed.')
os.unlink(config.PIDFILE)
class SignalCommand:
"""Common base class for simple, signal sending commands."""
implements(ICLISubCommand)
name = None
message = None
signal = None
def add(self, parser, command_parser):
"""See `ICLISubCommand`."""
command_parser.add_argument(
'-q', '--quiet',
default=False, action='store_true',
help=_("""\
Don't print status messages. Error messages are still printed to
standard error."""))
def process(self, args):
"""See `ICLISubCommand`."""
if not args.quiet:
print _(self.message)
kill_watcher(self.signal)
class Stop(SignalCommand):
"""Stop the Malman daemons."""
name = 'stop'
message = _("Shutting down Mailman's master qrunner")
signal = signal.SIGTERM
class Reopen(SignalCommand):
"""Reopen the Mailman daemons."""
name = 'reopen'
message = _('Reopening the Mailman qrunners')
signal = signal.SIGHUP
class Restart(SignalCommand):
"""Stop the Mailman daemons."""
implements(ICLISubCommand)
name = 'restart'
message = _('Restarting the Mailman qrunners')
signal = signal.SIGUSR1
|