diff --git a/oslo/rootwrap/cmd.py b/oslo/rootwrap/cmd.py index fe92054..fc0ff8f 100644 --- a/oslo/rootwrap/cmd.py +++ b/oslo/rootwrap/cmd.py @@ -44,6 +44,7 @@ RC_UNAUTHORIZED = 99 RC_NOCOMMAND = 98 RC_BADCONFIG = 97 RC_NOEXECFOUND = 96 +SIGNAL_BASE = 128 def _exit_error(execname, message, errorcode, log=True): @@ -106,8 +107,11 @@ def run_one_command(execname, config, filters, userargs): stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr) - obj.wait() - sys.exit(obj.returncode) + returncode = obj.wait() + # Fix returncode of Popen + if returncode < 0: + returncode = SIGNAL_BASE - returncode + sys.exit(returncode) except wrapper.FilterMatchNotExecutable as exc: msg = ("Executable not found: %s (filter match = %s)" diff --git a/tests/test_rootwrap.py b/tests/test_rootwrap.py index 5af33e1..17dfd2a 100644 --- a/tests/test_rootwrap.py +++ b/tests/test_rootwrap.py @@ -23,6 +23,7 @@ import mock from six import moves import testtools +from oslo.rootwrap import cmd from oslo.rootwrap import filters from oslo.rootwrap import wrapper @@ -567,3 +568,18 @@ class PathFilterTestCase(testtools.TestCase): os.path.realpath(self.TRAVERSAL_SYMLINK_WITHIN_DIR)] self.assertEqual(expected, self.f.get_command(args)) + + +class RunOneCommandTestCase(testtools.TestCase): + def _test_returncode_helper(self, returncode, expected): + with mock.patch.object(wrapper, 'start_subprocess') as mock_start: + with mock.patch('sys.exit') as mock_exit: + mock_start.return_value.wait.return_value = returncode + cmd.run_one_command(None, mock.Mock(), None, None) + mock_exit.assert_called_once_with(expected) + + def test_positive_returncode(self): + self._test_returncode_helper(1, 1) + + def test_negative_returncode(self): + self._test_returncode_helper(-1, 129)