135 lines
4.1 KiB
Python
Executable file
135 lines
4.1 KiB
Python
Executable file
#!/usr/bin/python
|
|
"""Service launcher that creates pidfiles and can redirect output to a file."""
|
|
import subprocess, sys, os, optparse, signal, pwd, grp, re
|
|
|
|
|
|
def stop_service(pidfile):
|
|
"""
|
|
Stop a service using a pidfile.
|
|
|
|
Read the first line of a file for an integer that should refer to a pid,
|
|
send a SIGTERM to that pid #.
|
|
@param pidfile: file to read for the process id number
|
|
"""
|
|
pidfh = open(pidfile)
|
|
pid = int(pidfh.readline())
|
|
os.kill(pid, signal.SIGTERM)
|
|
|
|
|
|
def start_service(cmd, pidfile, logfile=os.devnull, chdir=None):
|
|
"""
|
|
Start cmd in the background and write the pid to pidfile.
|
|
|
|
@param cmd: command to run with arguments
|
|
@param pidfile: pidfile to write the pid to
|
|
@param logfile: file to write stderr/stdout to
|
|
@param chdir: Directory to change to before starting the application
|
|
"""
|
|
logfh = open(logfile, 'a')
|
|
pidfh = open(pidfile, 'w')
|
|
proc = subprocess.Popen(cmd, stdout=logfh, stderr=logfh, cwd=chdir)
|
|
pidfh.write(str(proc.pid))
|
|
pidfh.close()
|
|
|
|
|
|
def get_user_name_id(user):
|
|
"""
|
|
Get the user id # and name.
|
|
|
|
@param user: integer or string containing either the uid #
|
|
or a string username
|
|
|
|
@returns a tuple of the user name, user id
|
|
"""
|
|
if re.match('\d+', str(user)):
|
|
pass_info = pwd.getpwuid(user)
|
|
else:
|
|
pass_info = pwd.getpwnam(user)
|
|
|
|
return pass_info[0], pass_info[2]
|
|
|
|
|
|
def get_group_name_id(group):
|
|
"""
|
|
Get the group id # and name
|
|
|
|
@param group: integer or string containing either the uid #
|
|
or a string username
|
|
|
|
@returns a tuple of group name, group id
|
|
"""
|
|
if re.match('\d+', str(group)):
|
|
group_info = grp.getgrgid(group)
|
|
else:
|
|
group_info = grp.getgrnam(group)
|
|
|
|
return group_info[0], group_info[2]
|
|
|
|
|
|
def set_group_user(group=None, user=None):
|
|
"""
|
|
Set the group and user id if gid or uid is defined.
|
|
|
|
@param group: Change the group id the program is run under
|
|
@param user: Change the user id the program is run under
|
|
"""
|
|
if group:
|
|
_, gid = get_group_name_id(group)
|
|
os.setgid(gid)
|
|
os.setegid(gid)
|
|
|
|
if user:
|
|
username, uid = get_user_name_id(user)
|
|
# Set environment for programs that use those to find running user
|
|
for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
|
|
os.environ[name] = username
|
|
os.setuid(uid)
|
|
os.seteuid(uid)
|
|
|
|
|
|
def main():
|
|
parser = optparse.OptionParser()
|
|
parser.allow_interspersed_args = False
|
|
parser.add_option('-l', '--logfile', action='store',
|
|
default=None,
|
|
help='File to redirect stdout to')
|
|
parser.add_option('-c', '--chdir', action='store',
|
|
default=None,
|
|
help='Change to dir before starting the process')
|
|
parser.add_option('-s', '--start-service', action='store_true',
|
|
default=False,
|
|
help='Start service')
|
|
parser.add_option('-k', '--stop-service', action='store_true',
|
|
default=False,
|
|
help='Stop service')
|
|
parser.add_option('-p', '--pidfile', action='store',
|
|
default=None,
|
|
help='Pid file location (Required)')
|
|
parser.add_option('-u', '--chuid', action='store',
|
|
default=None,
|
|
help='UID to run process as')
|
|
parser.add_option('-g', '--chgid', action='store',
|
|
default=None,
|
|
help='GID to run process as')
|
|
|
|
|
|
|
|
options, args = parser.parse_args()
|
|
|
|
if not options.pidfile:
|
|
print 'A pidfile must always be supplied'
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
|
|
set_group_user(group=options.chgid, user=options.chuid)
|
|
if options.start_service:
|
|
start_service(args, options.pidfile, options.logfile, options.chdir)
|
|
elif options.stop_service:
|
|
stop_service(options.pidfile)
|
|
else:
|
|
print 'Nothing to do, you must specify to start or stop a service'
|
|
parser.print_help()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|