Ejemplo n.º 1
0
    def run(self):
        """
        Runs the manhole loop. Only accepts one connection at a time because:

        * This thread is a daemon thread (exits when main thread exists).
        * The connection need exclusive access to stdin, stderr and stdout so it can redirect inputs and outputs.
        """
        self.serious.set()
        if signalfd and self.sigmask:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, self.sigmask)
        pthread_setname_np(self.ident, self.name)

        if self.bind_delay:
            _LOG("Delaying UDS binding %s seconds ..." % self.bind_delay)
            _ORIGINAL_SLEEP(self.bind_delay)

        sock = self.get_socket()
        while self.should_run:
            _LOG("Waiting for new connection (in pid:%s) ..." % os.getpid())
            try:
                client = ManholeConnectionThread(sock.accept()[0],
                                                 self.connection_handler,
                                                 self.daemon_connection)
                client.start()
                client.join()
            except (InterruptedError, socket.error) as e:
                if e.errno != errno.EINTR:
                    raise
                continue
            finally:
                client = None
Ejemplo n.º 2
0
 def test_return_previous_mask(self):
     """
     sigprocmask returns a list of the signals previously masked.
     """
     previous = signalfd.sigprocmask(signalfd.SIG_BLOCK, [1, 3, 5])
     result = signalfd.sigprocmask(signalfd.SIG_BLOCK, previous)
     self.assertEquals(result, [1, 3, 5])
Ejemplo n.º 3
0
    def run(self):
        child_fd = signalfd.signalfd(0, [signal.SIGCHLD], signalfd.SFD_NONBLOCK|signalfd.SFD_CLOEXEC)
        with os.fdopen(child_fd, 'rb') as child_signals:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGCHLD])
            with closing(cloexec(socket.socket(socket.AF_UNIX, socket.SOCK_STREAM))) as requests_sock:
                if os.path.exists(self.socket_name):
                    os.unlink(self.socket_name)
                requests_sock.bind(self.socket_name)
                requests_sock.listen(self.socket_backlog)
                try:
                    while 1:
                        qlen = len(self.queues)
                        logger.debug("Queues => %s workspaces", qlen)
                        for i, wq in enumerate(self.queues.values()):
                            if i + 1 == qlen:
                                logger.debug(" \_ %s", wq)
                            else:
                                logger.debug(" |_ %s", wq)

                        current_fds = [child_fd, requests_sock]
                        current_fds.extend(self.clients.keys())
                        read_ready, _, errors = select.select(current_fds, [], current_fds, 1)
                        for fd in read_ready:
                            if requests_sock == fd:
                                self.handle_accept(requests_sock)
                            elif fd in self.clients:
                                self.handle_request(fd)
                            elif fd == child_fd:
                                self.handle_signal(child_signals)
                        for fd in errors:
                            logger.error("Fd %r has error !", fd)
                finally:
                    for fd, (fh, _) in self.clients.items():
                        close(fh, fd)
Ejemplo n.º 4
0
    def run(self):
        """
        Runs the manhole loop. Only accepts one connection at a time because:

        * This thread is a daemon thread (exits when main thread exists).
        * The connection need exclusive access to stdin, stderr and stdout so it can redirect inputs and outputs.
        """
        self.serious.set()
        if signalfd and self.sigmask:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, self.sigmask)
        pthread_setname_np(self.ident, self.name)

        if self.bind_delay:
            _cry("Delaying UDS binding %s seconds ..." % self.bind_delay)
            _ORIGINAL_SLEEP(self.bind_delay)

        sock = self.get_socket()
        while True:
            _cry("Waiting for new connection (in pid:%s) ..." % os.getpid())
            try:
                client = ManholeConnection(sock.accept()[0], self.locals, self.daemon_connection)
                client.start()
                client.join()
            except (InterruptedError, socket.error) as e:
                if e.errno != errno.EINTR:
                    raise
                continue
            finally:
                client = None
Ejemplo n.º 5
0
    def run(self):
        cry('Started ManholeConnection thread. Checking credentials ...')
        if signalfd and self.sigmask:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, self.sigmask)
        pthread_setname_np(self.ident, "Manhole ----")

        pid, _, _ = self.check_credentials(self.client)
        pthread_setname_np(self.ident, "Manhole %s" % pid)
        self.handle(self.client)
Ejemplo n.º 6
0
    def run(self):
        cry('Started ManholeConnection thread. Checking credentials ...')
        if signalfd and self.sigmask:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, self.sigmask)
        pthread_setname_np(self.ident, "Manhole ----")

        pid, _, _ = self.check_credentials(self.client)
        pthread_setname_np(self.ident, "Manhole %s" % pid)
        self.handle(self.client)
Ejemplo n.º 7
0
def test_block_and_read():
    fd = signalfd.signalfd(-1, [signal.SIGUSR1], signalfd.SFD_CLOEXEC)
    try:
        signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR1])
        os.kill(os.getpid(), signal.SIGUSR1)
        si = signalfd.read_siginfo(fd)
        assert si.ssi_signo == signal.SIGUSR1
    finally:
        os.close(fd)
Ejemplo n.º 8
0
def test_block_and_read():
    fd = signalfd.signalfd(-1, [signal.SIGUSR1], signalfd.SFD_CLOEXEC)
    try:
        signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR1])
        os.kill(os.getpid(), signal.SIGUSR1)
        si = signalfd.read_siginfo(fd)
        assert si.ssi_signo == signal.SIGUSR1
    finally:
        os.close(fd)
Ejemplo n.º 9
0
 def test_invalid_how(self):
     """
     If a value other than SIG_BLOCK, SIG_UNBLOCK, or SIG_SETMASK is passed
     for the how argument to sigprocmask, ValueError is raised.
     """
     message = "value specified for how (1700) invalid"
     try:
         signalfd.sigprocmask(1700, [])
     except ValueError:
         type, value, traceback = sys.exc_info()
         self.assertEquals(str(value), message)
Ejemplo n.º 10
0
 def test_invalid_signal(self):
     """
     If an object in the iterable passed for the signals parameter to
     sigprocmask isn't an integer, TypeError is raised.
     """
     try:
         signalfd.sigprocmask(signalfd.SIG_BLOCK, [object()])
     except TypeError:
         type, value, traceback = sys.exc_info()
         self.assertEquals(str(value), "an integer is required")
     else:
         self.fail(
             "Expected non-integer signal to be rejected.")
Ejemplo n.º 11
0
 def test_invalid_signal_iterable(self):
     """
     If iterating over the value passed for the signals parameter to
     sigprocmask raises an exception, sigprocmask raises that exception.
     """
     class BrokenIter(object):
         def __iter__(self):
             raise RuntimeError("my __iter__ is broken")
     try:
         signalfd.sigprocmask(signalfd.SIG_BLOCK, BrokenIter())
     except RuntimeError:
         type, value, traceback = sys.exc_info()
         self.assertEquals(str(value), "my __iter__ is broken")
Ejemplo n.º 12
0
 def __init__(self, gdb_id):
   # Workaround -----------------------------------------------------------------
   # We need this as a workaround for the bug in GDB: https://sourceware.org/bugzilla/show_bug.cgi?id=17314
   # This is based in the fix done in GDB for Guile in this patch: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=patch;h=92d8d229d9a310ebfcfc13bf4a75a286c1add1ac
   import signal
   previous_mask = signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGCHLD, signal.SIGCONT, signal.SIGINT])
   try:
       EH.__init__(self, name="(gdb %s[plugin])" % gdb_id, as_daemon=True) # as_daemon=True otherwise GDB hangs
   finally:
       signalfd.sigprocmask(signalfd.SIG_SETMASK, previous_mask) # restore the mask for GDB
   # ----------------------------------------------------------------------------
       
   self.gdb_id = gdb_id
   self.queue = Queue.Queue(maxsize=1000000)
Ejemplo n.º 13
0
 def test_block(self):
     """
     When invoked with SIG_BLOCK, sigprocmask blocks the signals in the
     sigmask list.
     """
     self._handle_sigusr1()
     previous = signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR1])
     os.kill(os.getpid(), signal.SIGUSR1)
     try:
         # Expect to receive SIGUSR1 after unblocking it.
         signalfd.sigprocmask(signalfd.SIG_SETMASK, previous)
     except SomeException:
         pass
     else:
         self.fail(
             "Expected exception to be raised after unblocking SIGUSR1")
Ejemplo n.º 14
0
    def test_unblock(self):
        """
        When invoked with SIG_UNBLOCK, sigprocmask unblocks the signals in the
        sigmask list.
        """
        self._handle_sigusr1()
        previous = signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR1])
        self.addCleanup(signalfd.sigprocmask, signalfd.SIG_SETMASK, previous)
        signalfd.sigprocmask(signalfd.SIG_UNBLOCK, [signal.SIGUSR1])

        try:
            os.kill(os.getpid(), signal.SIGUSR1)
        except SomeException:
            pass
        else:
            self.fail(
                "Expected SIGUSR1 to trigger handler raising SomeException")
Ejemplo n.º 15
0
    def run(self):
        self.serious.set()
        if signalfd and self.sigmask:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, self.sigmask)
        pthread_setname_np(self.ident, self.name)

        sock, pid = self.get_socket()
        while True:
            cry("Waiting for a new connection (in pid %s) ..." % pid)
            try:
                client = ManholeConnection(sock.accept()[0], self.sigmask)
                client.start()
                client.join()
            except (InterruptedError, socket.error) as e:
                if e.errno != errno.EINTR:
                    raise
                continue
            finally:
                client = None
Ejemplo n.º 16
0
    def run(self):
        self.serious.set()
        if signalfd and self.sigmask:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, self.sigmask)
        pthread_setname_np(self.ident, self.name)

        sock, pid = self.get_socket()
        while True:
            cry("Waiting for a new connection (in pid %s) ..." % pid)
            try:
                client = ManholeConnection(sock.accept()[0], self.sigmask)
                client.start()
                client.join()
            except (InterruptedError, socket.error) as e:
                if e.errno != errno.EINTR:
                    raise
                continue
            finally:
                client = None
Ejemplo n.º 17
0
    def run(self):
        child_fd = signalfd.signalfd(
            -1, [signal.SIGCHLD], signalfd.SFD_NONBLOCK | signalfd.SFD_CLOEXEC)
        with os.fdopen(child_fd, "rb") as child_signals:
            signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGCHLD])
            with closing(
                    cloexec(socket.socket(
                        socket.AF_UNIX, socket.SOCK_STREAM))) as requests_sock:
                logger.info("Binding to %r", self.socket_path)
                if os.path.exists(self.socket_path):
                    os.unlink(self.socket_path)
                pending_socket_path = "%s-pending" % self.socket_path
                requests_sock.bind(pending_socket_path)
                requests_sock.listen(self.socket_backlog)
                os.rename(pending_socket_path, self.socket_path)
                try:
                    while 1:
                        qlen = len(self.queues)
                        logger.debug("Queues => %s workspaces", qlen)
                        for i, wq in enumerate(self.queues.values()):
                            if i + 1 == qlen:
                                logger.debug(" \_ %s", wq)
                            else:
                                logger.debug(" |_ %s", wq)

                        current_fds = [child_fd, requests_sock]
                        current_fds.extend(self.clients.keys())
                        read_ready, _, errors = select.select(
                            current_fds, [], current_fds, 1)
                        for fd in read_ready:
                            if requests_sock == fd:
                                self.handle_accept(requests_sock)
                            elif fd in self.clients:
                                self.handle_request(fd)
                            elif fd == child_fd:
                                self.handle_signal(child_signals)
                        for fd in errors:
                            logger.error("Fd %r has error !", fd)
                finally:
                    for fd, (fh, _) in self.clients.items():
                        close(fh, fd)
Ejemplo n.º 18
0
 def test_handle_signals(self):
     """
     After signalfd is called, if a signal is received which was in the
     sigmask list passed to that call, information about the signal can be
     read from the fd returned by that call.
     """
     fd = self.signalfd(-1, [signal.SIGUSR2])
     self.addCleanup(os.close, fd)
     previous = signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR2])
     self.addCleanup(signalfd.sigprocmask, signalfd.SIG_SETMASK, previous)
     os.kill(os.getpid(), signal.SIGUSR2)
     bytes = os.read(fd, 128)
     self.assertTrue(bytes)
Ejemplo n.º 19
0
    def _handle_sigusr1(self):
        old_handler = signal.signal(signal.SIGUSR1, raiser)
        self.addCleanup(signal.signal, signal.SIGUSR1, old_handler)

        # This depends on sigprocmask working a bit.  If it doesn't, then
        # this won't succeed in keeping the signal mask state sane.  But
        # there's nothing else we can do in that case.  This is necessary at
        # all because some environments start off with certain signals
        # masked for obscure reasons.  The intent is to provide the tests
        # with a consistent, predictable starting state and then restore the
        # environment's expectations after the test.
        old_mask = signalfd.sigprocmask(signalfd.SIG_SETMASK, [])
        self.addCleanup(signalfd.sigprocmask, signalfd.SIG_SETMASK, old_mask)
Ejemplo n.º 20
0
def run_server(args):
	"""
	It is important that we create the signal FD and block the signals before doing anything
	else. Otherwise, we may get interrupted partway during initialization, and the resources we
	have allocated thus far will not be released.
	"""
	sig_fd = signalfd.signalfd(-1, shutdown_signals, SFD_NONBLOCK | SFD_CLOEXEC)
	signalfd.sigprocmask(SIG_BLOCK, shutdown_signals)

	sock, epoll = None, None
	conn_dict = {}

	try:
		sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		sock.setblocking(False)
		sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		sock.bind(('0.0.0.0', SERVER_PORT))

		epoll = select.epoll(sizehint=2, flags=EPOLL_CLOEXEC)
		epoll.register(sig_fd, EPOLLIN)
		epoll.register(sock, EPOLLIN)

		sock.listen(SERVER_BACKLOG_SIZE)
		print("Listening on {}:{}.".format(socket.gethostname(), SERVER_PORT),
			file=sys.stderr, flush=True)
		listen(sock, sig_fd, conn_dict, epoll)
	except SystemExit:
		print("Terminated.", file=sys.stderr, flush=True)
		raise
	finally:
		if epoll:
			epoll.close()

		os.close(sig_fd)
		if sock:
			close_socket(sock)
		for conn, _ in conn_dict.values():
			close_socket(conn)
Ejemplo n.º 21
0
 def test_read_signals(self):
     """
     signalfd.read_signalfd should behave like test_handle_signals but
     return a SigInfo instance instead of raw bytes
     """
     fd = self.signalfd(-1, [signal.SIGUSR2])
     self.addCleanup(os.close, fd)
     previous = signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR2])
     self.addCleanup(signalfd.sigprocmask, signalfd.SIG_SETMASK, previous)
     os.kill(os.getpid(), signal.SIGUSR2)
     siginfo = signalfd.read_signalfd(fd)
     self.assertTrue(siginfo)
     self.assertEqual(siginfo.ssi_signo, signal.SIGUSR2)
     self.assertEqual(siginfo.ssi_pid, os.getpid())
Ejemplo n.º 22
0
 def start(self, loglevel, logfile):
     """Start to work !"""
     logging.basicConfig(
         level=loglevel,
         stream=logfile,
         format=
         "%(levelname)s|%(asctime)s|%(process)d|%(filename)s|%(funcName)s|%(lineno)d| %(message)s"
     )
     global _LOGGER
     _LOGGER = logging.getLogger(__name__)
     self.init_sockets()
     _LOGGER.info("Worker %d started", self.worker_id)
     fd = signalfd.signalfd(-1, [signal.SIGTERM], signalfd.SFD_CLOEXEC)
     signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGTERM])
     with os.fdopen(fd) as fo:
         poller = zmq.Poller()
         poller.register(self.rep_sock, zmq.POLLIN)
         poller.register(fo, zmq.POLLIN)
         while True:
             try:
                 items = dict(poller.poll(1000))
                 if self.rep_sock in items:
                     cmd = self.rep_sock.recv()
                     _LOGGER.debug("cmd received from client: '%s'", cmd)
                     self.process_cmd(cmd)
                     _LOGGER.debug("cmd '%s' processed", cmd)
                 if fo.fileno() in items:
                     _LOGGER.debug("Signal received on worker %d",
                                   self.worker_id)
                     break
             except KeyboardInterrupt:
                 _LOGGER.debug("Keyboard interrrupt received on worker %d",
                               self.worker_id)
                 break
     _LOGGER.debug("Stopping worker %d", self.worker_id)
     self.rep_sock.close()
Ejemplo n.º 23
0
     print("Sending signal to manhole thread ...")
     pthread_kill(manhole._INST.ident, signal.SIGUSR2)
     for i in range(TIMEOUT * 100):
         time.sleep(0.1)
 elif test_name == 'test_oneshot_on_usr2':
     manhole.install(oneshot_on='USR2')
     for i in range(TIMEOUT * 100):
         time.sleep(0.1)
 elif test_name.startswith('test_signalfd_weirdness'):
     if 'negative' in test_name:
         manhole.install(sigmask=None)
     else:
         manhole.install(sigmask=[signal.SIGCHLD])
     print('Starting ...')
     import signalfd
     signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGCHLD])
     fd = signalfd.signalfd(
         0, [signal.SIGCHLD],
         signalfd.SFD_NONBLOCK | signalfd.SFD_CLOEXEC)
     for i in range(200):
         print('Forking %s:' % i)
         pid = os.fork()
         print(' - [%s/%s] forked' % (i, pid))
         if pid:
             while 1:
                 print(' - [%s/%s] selecting on: %s' % (i, pid, [fd]))
                 read_ready, _, errors = select.select([fd], [], [fd],
                                                       1)
                 if read_ready:
                     try:
                         print(' - [%s/%s] reading from signalfd ...' %
Ejemplo n.º 24
0
     pthread_kill(manhole._INST.ident, signal.SIGUSR2)
     for i in range(TIMEOUT * 100):
         time.sleep(0.1)
 elif test_name == 'test_oneshot_on_usr2':
     manhole.install(oneshot_on='USR2')
     for i in range(TIMEOUT  * 100):
         time.sleep(0.1)
 elif test_name.startswith('test_signalfd_weirdness'):
     if 'negative' in test_name:
         manhole.install(sigmask=None)
     else:
         manhole.install(sigmask=[signal.SIGCHLD])
     time.sleep(0.3)  # give the manhole a bit enough time to start
     print('Starting ...')
     import signalfd
     signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGCHLD])
     fd = signalfd.signalfd(0, [signal.SIGCHLD], signalfd.SFD_NONBLOCK|signalfd.SFD_CLOEXEC)
     for i in range(200):
         print('Forking %s:' % i)
         pid = os.fork()
         print(' - [%s/%s] forked' % (i, pid))
         if pid:
             while 1:
                 print(' - [%s/%s] selecting on: %s' % (i, pid, [fd]))
                 read_ready, _, errors = select.select([fd], [], [fd], 1)
                 if read_ready:
                     try:
                         print(' - [%s/%s] reading from signalfd ...' % (i, pid))
                         print(' - [%s] read from signalfd: %r ' % (i, os.read(fd, 128)))
                         break
                     except OSError as exc:
Ejemplo n.º 25
0
            @partial(signal.signal, signal.SIGUSR1)
            def signal_handler(sig, _):
                print('Received signal %s' % sig)
                global signalled
                signalled = True

            if 'negative' in test_name:
                manhole.install(sigmask=None)
            else:
                manhole.install(sigmask=[signal.SIGUSR1])

            time.sleep(0.3)  # give the manhole a bit enough time to start
            print('Starting ...')
            import signalfd

            signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR1])
            sys.setcheckinterval(1)
            for i in range(100000):
                os.kill(os.getpid(), signal.SIGUSR1)
            print('signalled=%s' % signalled)
            time.sleep(TIMEOUT * 10)
        elif test_name == 'test_auth_fail':
            manhole.get_peercred = lambda _: (-1, -1, -1)
            manhole.install()
            time.sleep(TIMEOUT * 10)
        elif test_name == 'test_socket_path':
            manhole.install(socket_path=SOCKET_PATH)
            time.sleep(TIMEOUT * 10)
        elif test_name == 'test_daemon_connection':
            manhole.install(daemon_connection=True)
            time.sleep(TIMEOUT)
Ejemplo n.º 26
0
            @partial(signal.signal, signal.SIGUSR1)
            def signal_handler(sig, _):
                print('Received signal %s' % sig)
                global signalled
                signalled = True

            if 'negative' in test_name:
                manhole.install(sigmask=None)
            else:
                manhole.install(sigmask=[signal.SIGUSR1])

            time.sleep(0.3)  # give the manhole a bit enough time to start
            print('Starting ...')
            import signalfd

            signalfd.sigprocmask(signalfd.SIG_BLOCK, [signal.SIGUSR1])
            sys.setcheckinterval(1)
            for i in range(100000):
                os.kill(os.getpid(), signal.SIGUSR1)
            print('signalled=%s' % signalled)
            time.sleep(TIMEOUT * 10)
        elif test_name == 'test_auth_fail':
            manhole.get_peercred = lambda _: (-1, -1, -1)
            manhole.install()
            time.sleep(TIMEOUT * 10)
        elif test_name == 'test_socket_path':
            manhole.install(socket_path=SOCKET_PATH)
            time.sleep(TIMEOUT * 10)
        elif test_name == 'test_daemon_connection':
            manhole.install(daemon_connection=True)
            time.sleep(TIMEOUT)
Ejemplo n.º 27
0
 def __init__(self, mask = [signal.SIGCHLD]):
     self.mask = mask
     self.signal_handlers = {}
     IOHandler.__init__(self, signalfd.signalfd(-1, mask, signalfd.SFD_CLOEXEC | signalfd.SFD_NONBLOCK), usage="SignalManager")
     signalfd.sigprocmask(signalfd.SIG_BLOCK, mask)
Ejemplo n.º 28
0
 def __init__(self, mask = [signal.SIGCHLD, signal.SIGTSTP]):
     self.mask = mask
     self.signal_handlers = {}
     IOHandler.__init__(self, signalfd.signalfd(-1, mask, signalfd.SFD_CLOEXEC | signalfd.SFD_NONBLOCK), usage="SignalManager")
     signalfd.sigprocmask(signalfd.SIG_BLOCK, mask)