#!/usr/bin/env python # Written by Ross Cohen # See LICENSE.txt for license information. try: import psyco assert psyco.__version__ >= 0x010300f0 psyco.full() except: pass try: import Codeville.db except ImportError: import sys, os.path from os.path import dirname, abspath, join pypath = "lib/python%d.%d/site-packages" % \ (sys.version_info[0], sys.version_info[1]) base = dirname(dirname(abspath(sys.argv[0]))) sys.path[0:0] = [ join(base, pypath) ] # first place to look from Codeville.agent import Agent from getopt import getopt, GetoptError import os from os import path from resource import setrlimit, RLIMIT_CORE from signal import alarm, signal from signal import SIGALRM, SIGHUP, SIGPIPE, SIGINT, SIGTERM, SIG_IGN import socket import sys from tempfile import mkdtemp ppid = None agent = None def cleanup_handler(signum, foo): agent.cleanup() sys.exit(2) return def check_parent_exists(signum, foo): if ppid is not None: try: os.kill(ppid, 0) except OSError: cleanup_handler(signum, foo) alarm(10) return def usage(): stderr = sys.stderr print >> stderr, "Usage: %s [options] [command [args ...]]" % sys.argv[0] print >> stderr, "Options:" print >> stderr, " -c Generate C-shell commands on stdout." print >> stderr, " -s Generate Bourne shell commands on stdout" print >> stderr, " -k Kill the current agent." print >> stderr, " -d Debug mode." print >> stderr, " -a socket Bind agent socket to given name." print >> stderr, " -t life Default identity lifetime (seconds) (ignored)." sys.exit(1) def fork_stuff(agent, sock, args, c_flag): pid = os.fork() if pid != 0: sock.close() if len(args) == 0: if c_flag: print 'setenv %s %s' % ('CDV_AGENT_PID', pid) print 'setenv %s %s' % ('CDV_AUTH_SOCK', agent.auth_file) else: print '%s=%s; export %s;' % ('CDV_AGENT_PID', pid, 'CDV_AGENT_PID') print '%s=%s; export %s;' % ('CDV_AUTH_SOCK', agent.auth_file, 'CDV_AUTH_SOCK') print "echo Agent pid %d;" % (pid) sys.exit(0) os.environ['CDV_AGENT_PID'] = str(pid) os.environ['CDV_AUTH_SOCK'] = agent.auth_file try: os.execvp(args[0], args) except OSError, msg: print msg sys.exit(1) os.setsid() os.chdir('/') fd = open('/dev/null', 'r+') os.dup2(fd.fileno(), sys.stdin.fileno()) os.dup2(fd.fileno(), sys.stdout.fileno()) os.dup2(fd.fileno(), sys.stderr.fileno()) # set rlimit to prevent core dumping setrlimit(RLIMIT_CORE, (0, 0)) return def run(args): global ppid global agent auth_path = None auth_file = None os.setegid(os.getgid()) os.setgid(os.getgid()) try: optlist, args = getopt(args, 'a:cdkst:') except GetoptError: usage() c_flag, d_flag, k_flag, s_flag = 0, 0, 0, 0 for (opt, arg) in optlist: if opt == '-a': auth_file = arg elif opt == '-c': if s_flag: usage() c_flag += 1 elif opt == '-d': if d_flag: usage() d_flag += 1 elif opt == '-k': k_flag += 1 elif opt == '-s': if c_flag: usage() s_flag += 1 elif opt == '-t': # XXX: for compatibility pass if len(args) and (c_flag or k_flag or s_flag or d_flag): usage() if len(args) and not c_flag and not s_flag: try: shell = os.environ['SHELL'] except KeyError: pass else: if shell.endswith('csh'): c_flag = 1 if k_flag: try: kpid = int(os.environ['CDV_AGENT_PID']) except KeyError: 'CDV_AGENT_PID is not set, cannot kill agent' sys.exit(1) if kpid < 1: print 'CDV_AGENT_PID=%d, which is not a good PID' % (kpid) sys.exit(1) try: os.kill(kpid, SIGTERM) except OSError, msg: print msg sys.exit(1) if c_flag: print 'unsetenv %s;' % ('CDV_AUTH_SOCK') print 'unsetenv %s;' % ('CDV_AGENT_PID') else: print 'unset %s;' % ('CDV_AUTH_SOCK') print 'unset %s;' % ('CDV_AGENT_PID') print 'echo Agent pid %d killed;' % (kpid) sys.exit(0) agent = Agent() ppid = os.getpid() if auth_file is None: auth_path = mkdtemp('', 'cdv-') auth_file = path.join(auth_path, 'agent.' + str(ppid)) try: sock = agent.listen_sock(auth_path, auth_file) if sock is None: sys.exit(1) except socket.error, reason: print reason[1] sys.exit(1) if d_flag: if c_flag: print 'setenv %s %s' % ('CDV_AUTH_SOCK', agent.auth_file) else: print '%s=%s; export %s;' % ('CDV_AUTH_SOCK', agent.auth_file, 'CDV_AUTH_SOCK') print "echo Agent pid %d;" % (ppid) else: fork_stuff(agent, sock, args, c_flag) # periodically check that parent exists if len(args): signal(SIGALRM, check_parent_exists) alarm(10) if not d_flag: signal(SIGINT, SIG_IGN) signal(SIGPIPE, SIG_IGN) signal(SIGHUP, cleanup_handler) signal(SIGTERM, cleanup_handler) agent.listen() return if __name__ == '__main__': sys.exit(run(sys.argv[1:]))