#!/usr/bin/env python
"""fanotify: wrapper aroudn the fanotify family of syscalls for watching for file modifcation"""
from __future__ import print_function

from cffi import FFI as _FFI
from os import O_RDONLY, O_WRONLY, O_RDWR
from os import fdopen
import errno as _errno

from warnings import warn

warn(PendingDeprecationWarning(), "The seccomp module is deprecated in favour of the official bindings, please consider upgrading")

READ_EVENTS_MAX = 10

_ffi = _FFI()
_ffi.cdef("""

typedef void * scmp_filter_ctx;

scmp_filter_ctx seccomp_init(uint32_t def_action);
int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action);
void seccomp_release(scmp_filter_ctx ctx);
int seccomp_merge(scmp_filter_ctx dst, scmp_filter_ctx src);
int seccomp_load(scmp_filter_ctx ctx);

typedef uint64_t scmp_datum_t;

struct scmp_arg_cmp {
    unsigned int arg;
    enum scmp_compare op;
    scmp_datum_t datum_a;
    scmp_datum_t datum_b;
};


int seccomp_rule_add(scmp_filter_ctx ctx, uint32_t action,
                     int syscall, unsigned int arg_cnt, ...);
int seccomp_rule_add_exact(scmp_filter_ctx ctx, uint32_t action,
                           int syscall, unsigned int arg_cnt, ...);

int seccomp_rule_add_array(scmp_filter_ctx ctx,
                           uint32_t action, int syscall,
                           unsigned int arg_cnt,
                           const struct scmp_arg_cmp *arg_array);
int seccomp_rule_add_exact_array(scmp_filter_ctx ctx,
                                 uint32_t action, int syscall,
                                 unsigned int arg_cnt,
                                 const struct scmp_arg_cmp *arg_array);

//# Default actions
#define SCMP_ACT_KILL ...
#define SCMP_ACT_TRAP ...
#define SCMP_ACT_ALLOW ...
uint64_t _SCMP_ACT_ERRNO(uint64_t code);
uint64_t _SCMP_ACT_TRACE(uint64_t code);

//#Valid comparison op values are as follows:
#define SCMP_CMP_NE ...
#define SCMP_CMP_LT ...
#define SCMP_CMP_LE ...
#define SCMP_CMP_EQ ...
#define SCMP_CMP_GE ...
#define SCMP_CMP_GT ...
#define SCMP_CMP_MASKED_EQ ...

//#SCMP_SYS macro wont work how we want it, grab the syscall numbers manually
#define __NR_SCMP_ERROR ...
#define __NR_socket ...
#define __NR_bind ...
#define __NR_connect ...
#define __NR_listen ...
#define __NR_accept ...
#define __NR_getsockname ...
#define __NR_getpeername ...
#define __NR_socketpair ...
#define __NR_send ...
#define __NR_recv ...
#define __NR_sendto ...
#define __NR_recvfrom ...
#define __NR_shutdown ...
#define __NR_setsockopt ...
#define __NR_getsockopt ...
#define __NR_sendmsg ...
#define __NR_recvmsg ...
#define __NR_accept4 ...
#define __NR_recvmmsg ...
#define __NR_sendmmsg ...
#define __NR_semop ...
#define __NR_semget ...
#define __NR_semctl ...
#define __NR_semtimedop ...
#define __NR_msgsnd ...
#define __NR_msgrcv ...
#define __NR_msgget ...
#define __NR_msgctl ...
#define __NR_shmat ...
#define __NR_shmdt ...
#define __NR_shmget ...
#define __NR_shmctl ...
#define __NR_arch_prctl ...
#define __NR_bdflush ...
#define __NR_break ...
#define __NR_chown32 ...
#define __NR_epoll_ctl_old ...
#define __NR_epoll_wait_old ...
#define __NR_fadvise64_64 ...
#define __NR_fchown32 ...
#define __NR_fcntl64 ...
#define __NR_fstat64 ...
#define __NR_fstatat64 ...
#define __NR_fstatfs64 ...
#define __NR_ftime ...
#define __NR_ftruncate64 ...
#define __NR_getegid32 ...
#define __NR_geteuid32 ...
#define __NR_getgid32 ...
#define __NR_getgroups32 ...
#define __NR_getresgid32 ...
#define __NR_getresuid32 ...
#define __NR_getuid32 ...
#define __NR_gtty ...
#define __NR_idle ...
#define __NR_ipc ...
#define __NR_lchown32 ...
#define __NR__llseek ...
#define __NR_lock ...
#define __NR_lstat64 ...
#define __NR_mmap2 ...
#define __NR_mpx ...
#define __NR_newfstatat ...
#define __NR__newselect ...
#define __NR_nice ...
#define __NR_oldfstat ...
#define __NR_oldlstat ...
#define __NR_oldolduname ...
#define __NR_oldstat ...
#define __NR_olduname ...
#define __NR_prof ...
#define __NR_profil ...
#define __NR_readdir ...
#define __NR_security ...
#define __NR_sendfile64 ...
#define __NR_setfsgid32 ...
#define __NR_setfsuid32 ...
#define __NR_setgid32 ...
#define __NR_setgroups32 ...
#define __NR_setregid32 ...
#define __NR_setresgid32 ...
#define __NR_setresuid32 ...
#define __NR_setreuid32 ...
#define __NR_setuid32 ...
#define __NR_sgetmask ...
#define __NR_sigaction ...
#define __NR_signal ...
#define __NR_sigpending ...
#define __NR_sigprocmask ...
#define __NR_sigreturn ...
#define __NR_sigsuspend ...
#define __NR_socketcall ...
#define __NR_ssetmask ...
#define __NR_stat64 ...
#define __NR_statfs64 ...
#define __NR_stime ...
#define __NR_stty ...
#define __NR_truncate64 ...
#define __NR_tuxcall ...
#define __NR_ugetrlimit ...
#define __NR_ulimit ...
#define __NR_umount ...
#define __NR_vm86 ...
#define __NR_vm86old ...
#define __NR_waitpid ...
#define __NR_create_module ...
#define __NR_get_kernel_syms ...
#define __NR_get_thread_area ...
#define __NR_nfsservctl ...
#define __NR_query_module ...
#define __NR_set_thread_area ...
#define __NR__sysctl ...
#define __NR_uselib ...
#define __NR_vserver ...
#define __NR_arm_fadvise64_64 ...
#define __NR_arm_sync_file_range ...
#define __NR_finit_module ...
#define __NR_pciconfig_iobase ...
#define __NR_pciconfig_read ...
#define __NR_pciconfig_write ...
#define __NR_sync_file_range2 ...
#define __NR_syscall ...
#define __NR_afs_syscall ...
#define __NR_fadvise64 ...
#define __NR_getpmsg ...
#define __NR_ioperm ...
#define __NR_iopl ...
#define __NR_kcmp ...
#define __NR_migrate_pages ...
#define __NR_modify_ldt ...
#define __NR_putpmsg ...
#define __NR_sync_file_range ...
""")

_C = _ffi.verify("""
#include <seccomp.h>

uint64_t _SCMP_ACT_ERRNO(uint64_t code) {
    return 0x7ff00000U | (code & 0x0000ffffU);
}
uint64_t _SCMP_ACT_TRACE(uint64_t code) {
    return 0x00050000U | (code & 0x0000ffffU);
}

""", libraries=['seccomp'], ext_package="butter")


def condition(arg=0, comparison=_C.SCMP_CMP_EQ, arg1=_ffi.NULL, arg2=_ffi.NULL):
    """Initalise a new struct_arg_cmp object
    :parama arg int: Which argument to the syscall the test should be performed on
    :parama comparison: The type of comparison to make (SCMP_CMP_*)
    :parama arg1 int: argument 1 for the comaprison
    :parama arg2 int: argument 2 for the comparison (not always used)
    """
    rule = _ffi.new('struct scmp_arg_cmp *')
    rule.arg = arg
    rule.op = comparison
    rule.datum_a = _ffi.cast('uint64_t', arg1)
    rule.datum_b = _ffi.cast('uint64_t', arg2)

    return rule
