﻿#!/usr/bin/env python

import os, sys, re


try:
    import fcntl
except ImportError:
    raise OSError, "Only runs on unix!"

import signal
from ctypes import *          #ugh, but just for this exercise
from ctypes import util

#######################################
# sigaction / siginfo structs
#######################################
# struct sigaction {
#    void (*sa_handler)(int);
#    void (*sa_sigaction)(int, siginfo_t *, void *);
#    sigset_t sa_mask;
#    int sa_flags;
#    void (*sa_restorer)(void);
# }
######################################
class sigval(Union):
    _fields_ = [
    ('sival_int', c_int),
    ('sival_ptr', c_void_p),
]

class __siginfo(Structure):
    _fields_ = [
    ('si_signo', c_int),
    ('si_errno', c_int),
    ('si_code', c_int),
    ('si_pid', c_uint),
    ('si_uid', c_uint),
    ('si_status', c_int),
    ('si_addr', c_void_p),
    ('si_value', sigval),
    ('si_band', c_long),
    ('pad', c_ulong * 7),
]

siginfo_t = __siginfo

class __sigaction_u(Union):
    _fields_ = [
    ('__sa_handler', CFUNCTYPE(None, c_int)),
    ('__sa_sigaction', CFUNCTYPE(None, c_int, 
                                 POINTER(siginfo_t), 
                                 c_void_p)),
]

sigaction_u = __sigaction_u

class __sigaction(Structure):
    _fields_ = [
    ('__sigaction_u',sigaction_u),
    ('sa_tramp', CFUNCTYPE(None, c_void_p, 
                           c_int, c_int, 
                           POINTER(siginfo_t), c_void_p)),
    ('sa_mask', c_uint),
    ('sa_flags', c_int),
]

class sigaction(Structure):
    _fields_ = [
    ('__sigaction_u', sigaction_u),
    ('sa_mask', c_uint),
    ('sa_flags', c_int),
]
#######################################
# END sigaction / siginfo structs
######################################

#call back that should be signalled, void so return nothing
def detailed_callback(signalno, siginfostruct, data):
    print "detailed callback: ", signalno, \
                                 siginfostruct, \
                                 data

#ctypes prototype implementation
C_PROTOTYPE_SIGNHANDLER = CFUNCTYPE(None, c_int, 
                                    POINTER(__siginfo), c_void_p)

#cast callback
sighandler_cb = C_PROTOTYPE_SIGNHANDLER(detailed_callback)


#####################################
# globals/literals
#####################################
ABS_PATH_LIBC = util.find_library('libc')
FCNTL_FLAGS= [fcntl.DN_MODIFY,fcntl.DN_CREATE,fcntl.DN_DELETE,fcntl.DN_RENAME]
FCNTL_BIT_FLAG = reduce(lambda x, y: x | y, FCNTL_FLAGS) | fcntl.DN_MULTISHOT


#get library
__clib = cdll.LoadLibrary(ABS_PATH_LIBC) 
assert __clib is not None 

#struct sigaction act;
act = sigaction()     


#act.sa_sigaction = handler;                        
act.__sigaction_u.sa_sigaction = sighandler_cb 

#sigemptyset(&act.sa_mask); 
#python2.6 has byref(act, offset),how can i port this over?  
#maybe addressof(act)+sizeof(sigaction.sa_mask)*(position_in_sigaction)
rc = __clib.sigemptyset(byref(act)) 
assert rc == 0

#act.sa_flags = SA_SIGINFO;
#/usr/include/bit/signum.h SA_SIGINFO
#TODO: look this up from python
act.sa_flags = 4; 


#sigaction(SIGRTMIN, &act, NULL);    
#signal.signal( signal.SIGRTMIN, sighandler_cb )                          
rc = __clib.sigaction( signal.SIGRTMIN, byref(act), None )             
assert rc == 0


#fd stuff, open cwd, monitor for changes, should invoke
#my callback..
__fd = os.open(os.getcwd(), os.O_RDONLY | os.O_NONBLOCK)     
__clib.fcntl( __fd, fcntl.F_SETSIG, signal.SIGRTMIN)
__clib.fcntl( __fd, fcntl.F_NOTIFY, FCNTL_BIT_FLAG )
 
import time
while True:
    signal.pause()