summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2013-03-29 20:13:45 +0100
committerArthur de Jong <arthur@arthurdejong.org>2013-03-29 20:13:45 +0100
commit11b1739afc43b5e444a5ac173b08b13b5b5fbc07 (patch)
treede6c8fe916409b12932fe54df040a97f9f74b2f1
parent65a65adbf953ee8da43a76db2cd03a064a80cd46 (diff)
Functionality for clearing the nscd cache in pynslcd
-rw-r--r--pynslcd/Makefile.am2
-rw-r--r--pynslcd/nscd.py107
2 files changed, 108 insertions, 1 deletions
diff --git a/pynslcd/Makefile.am b/pynslcd/Makefile.am
index cff5629..6203d12 100644
--- a/pynslcd/Makefile.am
+++ b/pynslcd/Makefile.am
@@ -20,7 +20,7 @@
pynslcddir = $(datadir)/pynslcd
pynslcd_PYTHON = pynslcd.py attmap.py cache.py cfg.py common.py expr.py \
- mypidfile.py search.py tio.py \
+ mypidfile.py nscd.py search.py tio.py \
alias.py ether.py group.py host.py netgroup.py network.py \
pam.py passwd.py protocol.py rpc.py service.py shadow.py
nodist_pynslcd_PYTHON = constants.py
diff --git a/pynslcd/nscd.py b/pynslcd/nscd.py
new file mode 100644
index 0000000..89cb483
--- /dev/null
+++ b/pynslcd/nscd.py
@@ -0,0 +1,107 @@
+
+# nscd.py - functions for invalidating the nscd cache
+#
+# 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 struct
+
+
+# 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',
+ )
+_char_to_db = dict((reversed(item) for item in _db_to_char.items()))
+
+
+def exec_invalidate(db):
+ logging.debug('nscd_invalidator: nscd -i %s', db)
+ try:
+ p = subprocess.Popen(['nscd', '-i', 'passwd'],
+ 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('nscd_invalidator: nscd -i %s (pid %d) success%s',
+ db, p.pid, output)
+ elif p.returncode > 0:
+ logging.debug('nscd_invalidator: nscd -i %s (pid %d) failed (%d)%s',
+ db, p.pid, p.returncode, output)
+ else: # p.returncode < 0
+ logging.error('nscd_invalidator: nscd -i %s (pid %d) killed by signal %d%s',
+ db, p.pid, -p.returncode, output)
+ except:
+ logging.warn('nscd_invalidator: nscd -i %s failed', db, exc_info=True)
+
+
+def loop(fd):
+ # set process title
+ try:
+ import setproctitle
+ setproctitle.setproctitle('(nscd 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)
+ # FIXME: define the characters and maps somewhere
+ if db == '':
+ break
+ db = _char_to_db.get(db, None)
+ if db:
+ exec_invalidate(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
+ db = _db_to_char.get(db, '')
+ try:
+ os.write(signalfd, db)
+ except:
+ logging.warn('nscd_invalidator: nscd -i %s failed', db, exc_info=True)