Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/pynslcd/invalidator.py
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2013-07-26 14:59:43 +0200
committerArthur de Jong <arthur@arthurdejong.org>2013-07-26 14:59:43 +0200
commite1b0399ee018d217cd50267cef03c28dfdb32fbf (patch)
tree56229ff26cd878176707d9672fe65148b6073c5a /pynslcd/invalidator.py
parent6054499f9a9952593ccadc83182e01d39ff62f12 (diff)
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.
Diffstat (limited to 'pynslcd/invalidator.py')
-rw-r--r--pynslcd/invalidator.py112
1 files changed, 112 insertions, 0 deletions
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)