Restore SIGPIPE default action for subprocesses

Python ignores SIGPIPE on startup, because it prefers to check every
write and raise an IOError exception rather than taking the signal. Most
Unix subprocesses don't expect to work this way. This patch (adapted
from Colin Watson's post at http://tinyurl.com/2a7mzh5) sets SIGPIPE
back to the default action for quantum.agent.linux.utils.execute,
quantum.common.utils.execute and quantum-rootwrap created subprocesses.

Fixes bug 1053364

Change-Id: Ib805f1f8846c245b75a5ea64278c840b823c1fb2
This commit is contained in:
Thierry Carrez 2012-09-20 14:42:53 +02:00 committed by Chuck Short
parent 5a5dec2d65
commit 3bbf281b15
3 changed files with 24 additions and 0 deletions

View File

@ -38,6 +38,7 @@
import ConfigParser import ConfigParser
import os import os
import signal
import subprocess import subprocess
import sys import sys
@ -47,6 +48,12 @@ RC_NOCOMMAND = 98
RC_BADCONFIG = 97 RC_BADCONFIG = 97
def _subprocess_setup():
# Python installs a SIGPIPE handler by default. This is usually not what
# non-Python subprocesses expect.
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
if __name__ == '__main__': if __name__ == '__main__':
# Split arguments, require at least a command # Split arguments, require at least a command
execname = sys.argv.pop(0) execname = sys.argv.pop(0)
@ -84,6 +91,7 @@ if __name__ == '__main__':
stdin=sys.stdin, stdin=sys.stdin,
stdout=sys.stdout, stdout=sys.stdout,
stderr=sys.stderr, stderr=sys.stderr,
preexec_fn=_subprocess_setup,
env=filtermatch.get_environment(userargs)) env=filtermatch.get_environment(userargs))
obj.wait() obj.wait()
sys.exit(obj.returncode) sys.exit(obj.returncode)

View File

@ -21,6 +21,7 @@ import fcntl
import logging import logging
import os import os
import shlex import shlex
import signal
import socket import socket
import struct import struct
@ -30,6 +31,12 @@ from eventlet.green import subprocess
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
def _subprocess_setup():
# Python installs a SIGPIPE handler by default. This is usually not what
# non-Python subprocesses expect.
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
def execute(cmd, root_helper=None, process_input=None, addl_env=None, def execute(cmd, root_helper=None, process_input=None, addl_env=None,
check_exit_code=True, return_stderr=False): check_exit_code=True, return_stderr=False):
if root_helper: if root_helper:
@ -42,6 +49,7 @@ def execute(cmd, root_helper=None, process_input=None, addl_env=None,
env.update(addl_env) env.update(addl_env)
obj = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, obj = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
preexec_fn=_subprocess_setup,
env=env) env=env)
_stdout, _stderr = (process_input and _stdout, _stderr = (process_input and

View File

@ -23,6 +23,7 @@
import logging import logging
import os import os
import signal
import subprocess import subprocess
import uuid import uuid
@ -47,6 +48,12 @@ def boolize(subject):
return subject return subject
def _subprocess_setup():
# Python installs a SIGPIPE handler by default. This is usually not what
# non-Python subprocesses expect.
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
def execute(cmd, process_input=None, addl_env=None, check_exit_code=True): def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
logging.debug("Running cmd: %s", cmd) logging.debug("Running cmd: %s", cmd)
env = os.environ.copy() env = os.environ.copy()
@ -54,6 +61,7 @@ def execute(cmd, process_input=None, addl_env=None, check_exit_code=True):
env.update(addl_env) env.update(addl_env)
obj = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, obj = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
preexec_fn=_subprocess_setup,
env=env) env=env)
result = None result = None
if process_input is not None: if process_input is not None: