1#!/usr/bin/env python
2#
3#   (C) 2001 by Argonne National Laboratory.
4#       See COPYRIGHT in top-level directory.
5#
6"""
7usage: mpdsigjob  sigtype  [-j jobid OR -a jobalias] [-s|g]
8    sigtype must be the first arg
9    jobid can be obtained via mpdlistjobs and is of the form:
10        jobnum@mpdid where mpdid is mpd where first process runs, e.g.:
11            1@linux02_32996 (may need \@ in some shells)
12            1  is sufficient if you are on the machine where the job started
13    one of -j or -a must be specified (but only one)
14    -s or -g specify whether to signal the single user process or its group (default is g)
15Delivers a Unix signal to all the application processes in the job
16"""
17from time import ctime
18__author__ = "Ralph Butler and Rusty Lusk"
19__date__ = ctime()
20__version__ = "$Revision: 1.21 $"
21__credits__ = ""
22
23
24from os     import environ, getuid, close, path
25from sys    import argv, exit
26from socket import socket, fromfd, AF_UNIX, SOCK_STREAM
27from signal import signal, SIG_DFL, SIGINT, SIGTSTP, SIGCONT, SIGALRM
28from  mpdlib  import  mpd_set_my_id, mpd_uncaught_except_tb, mpd_print, \
29                      mpd_handle_signal, mpd_get_my_username, MPDConClientSock, MPDParmDB
30
31def mpdsigjob():
32    import sys    # to get access to excepthook in next line
33    sys.excepthook = mpd_uncaught_except_tb
34    if len(argv) < 3  or  argv[1] == '-h'  or  argv[1] == '--help':
35        usage()
36    signal(SIGINT, sig_handler)
37    mpd_set_my_id(myid='mpdsigjob')
38    sigtype = argv[1]
39    if sigtype.startswith('-'):
40        sigtype = sigtype[1:]
41    if sigtype.startswith('SIG'):
42        sigtype = sigtype[3:]
43    import signal as tmpsig  # just to get valid SIG's
44    if sigtype.isdigit():
45        if int(sigtype) > tmpsig.NSIG:
46            print 'invalid signum: %s' % (sigtype)
47            exit(-1)
48    else:
49	if not tmpsig.__dict__.has_key('SIG' + sigtype):
50	    print 'invalid sig type: %s' % (sigtype)
51	    exit(-1)
52    jobalias = ''
53    jobnum = ''
54    mpdid = ''
55    single_or_group = 'g'
56    i = 2
57    while i < len(argv):
58        if argv[i] == '-a':
59            if jobnum:      # should not have both alias and jobid
60                print '** cannot specify both jobalias and jobid'
61                usage()
62            jobalias = argv[i+1]
63            i += 1
64            jobnum = '0'
65        elif argv[i] == '-j':
66            if jobalias:    # should not have both alias and jobid
67                print '** cannot specify both jobalias and jobid'
68                usage()
69            jobid = argv[i+1]
70            i += 1
71            sjobid = jobid.split('@')
72            jobnum = sjobid[0]
73            if len(sjobid) > 1:
74                mpdid = sjobid[1]
75        elif argv[i] == '-s':
76            single_or_group = 's'
77        elif argv[i] == '-g':
78            single_or_group = 'g'
79        else:
80            print '** unrecognized arg: %s' % (argv[i])
81            usage()
82        i += 1
83
84    parmdb = MPDParmDB(orderedSources=['cmdline','xml','env','rcfile','thispgm'])
85    parmsToOverride = {
86                        'MPD_USE_ROOT_MPD'            :  0,
87                        'MPD_SECRETWORD'              :  '',
88                      }
89    for (k,v) in parmsToOverride.items():
90        parmdb[('thispgm',k)] = v
91    parmdb.get_parms_from_env(parmsToOverride)
92    parmdb.get_parms_from_rcfile(parmsToOverride)
93    if getuid() == 0  or  parmdb['MPD_USE_ROOT_MPD']:
94        fullDirName = path.abspath(path.split(argv[0])[0])  # normalize
95        mpdroot = path.join(fullDirName,'mpdroot')
96        conSock = MPDConClientSock(mpdroot=mpdroot,secretword=parmdb['MPD_SECRETWORD'])
97    else:
98        conSock = MPDConClientSock(secretword=parmdb['MPD_SECRETWORD'])
99
100    msgToSend = {'cmd' : 'mpdsigjob', 'sigtype': sigtype, 'jobnum' : jobnum,
101                 'mpdid' : mpdid, 'jobalias' : jobalias, 's_or_g' : single_or_group,
102                 'username' : mpd_get_my_username() }
103    conSock.send_dict_msg(msgToSend)
104    msg = conSock.recv_dict_msg(timeout=5.0)
105    if not msg:
106        mpd_print(1,'no msg recvd from mpd before timeout')
107    if msg['cmd'] != 'mpdsigjob_ack':
108        if msg['cmd'] == 'already_have_a_console':
109            mpd_print(1,'mpd already has a console (e.g. for long ringtest); try later')
110        else:
111            mpd_print(1,'unexpected message from mpd: %s' % (msg) )
112        exit(-1)
113    if not msg['handled']:
114        print 'job not found'
115        exit(-1)
116    conSock.close()
117
118def sig_handler(signum,frame):
119    mpd_handle_signal(signum,frame)  # not nec since I exit next
120    exit(-1)
121
122def usage():
123    print __doc__
124    exit(-1)
125
126
127if __name__ == '__main__':
128    mpdsigjob()
129