From e1b0399ee018d217cd50267cef03c28dfdb32fbf Mon Sep 17 00:00:00 2001 From: Arthur de Jong Date: Fri, 26 Jul 2013 14:59:43 +0200 Subject: Rename nscd_invalidate option to reconnect_invalidate This also renames the internal nscd module to invalidator for both nslcd and pynslcd. The new invalidator module is now no longer nscd-specific. --- pynslcd/invalidator.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 pynslcd/invalidator.py (limited to 'pynslcd/invalidator.py') diff --git a/pynslcd/invalidator.py b/pynslcd/invalidator.py new file mode 100644 index 0000000..98c0783 --- /dev/null +++ b/pynslcd/invalidator.py @@ -0,0 +1,112 @@ + +# invalidator.py - functions for invalidating external caches +# +# Copyright (C) 2013 Arthur de Jong +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +import fcntl +import logging +import os +import subprocess + +import cfg + + +# the file descriptor used for sending messages to the child process +signalfd = None + + +# mapping between map name and signal character +_db_to_char = dict( + aliases='A', ethers='E', group='G', hosts='H', netgroup='U', + networks='N', passwd='P', protocols='L', rpc='R', services='V', + shadow='S', nfsidmap='F', + ) +_char_to_db = dict((reversed(item) for item in _db_to_char.items())) + + +def exec_invalidate(*args): + cmd = ' '.join(args) + logging.debug('invalidator: %s', cmd) + try: + p = subprocess.Popen(args, bufsize=4096, close_fds=True, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + output, ignored = p.communicate() + if output: + output = ': %s' % output[:1024].strip() + if p.returncode == 0: + logging.debug('invalidator: %s (pid %d) success%s', + cmd, p.pid, output) + elif p.returncode > 0: + logging.debug('invalidator: %s (pid %d) failed (%d)%s', + cmd, p.pid, p.returncode, output) + else: # p.returncode < 0 + logging.error('invalidator: %s (pid %d) killed by signal %d%s', + cmd, p.pid, -p.returncode, output) + except: + logging.warn('invalidator: %s failed', cmd, exc_info=True) + + +def loop(fd): + # set process title + try: + import setproctitle + setproctitle.setproctitle('(invalidator)') + except ImportError: + pass + # set up clean environment + os.chdir('/') + os.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin' + while True: + db = os.read(fd, 1) + if db == '': + break # close process down + db = _char_to_db.get(db, None) + if db == 'nfsidmap': + exec_invalidate('nfsidmap', '-c') + else if db: + exec_invalidate('nscd', '-i', db) + + +def start_invalidator(): + r, w = os.pipe() + # mark write end as non-blocking + flags = fcntl.fcntl(w, fcntl.F_GETFL) + fcntl.fcntl(w, fcntl.F_SETFL, flags | os.O_NONBLOCK) + cpid = os.fork() + if cpid == 0: + # we are the child + os.close(w) + loop(r) + os._exit(1) + # we are the parent + global signalfd + signalfd = w + os.close(r) + + +def invalidate(db=None): + if signalfd is None: + return # nothing to do + if db: + db = _db_to_char.get(db, '') + else: + db = ''.join(_db_to_char[x] for x in cfg.reconnect_invalidate) + try: + os.write(signalfd, db) + except: + logging.warn('requesting invalidation (%s) failed', db, exc_info=True) -- cgit v1.2.3