-- ffi definitions of Linux types

local require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string = 
require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string

local abi = require "syscall.abi"

local ffi = require "ffi"

require "syscall.ffitypes"

local arch = require("syscall.linux." .. abi.arch .. ".ffi") -- architecture specific definitions

local defs = {}

local function append(str) defs[#defs + 1] = str end

append [[
typedef uint32_t mode_t;
typedef unsigned short int sa_family_t;
typedef uint64_t rlim64_t;
typedef unsigned long nlink_t;
typedef unsigned long ino_t;
typedef long time_t;
typedef int32_t daddr_t;
typedef long blkcnt_t;
typedef long blksize_t;
typedef int32_t clockid_t;
typedef long clock_t;
typedef uint32_t off32_t; /* only used for eg mmap2 on Linux */
typedef uint32_t le32; /* this is little endian - not really using it yet */
typedef uint32_t id_t;
typedef unsigned int tcflag_t;
typedef unsigned int speed_t;
typedef int timer_t;
typedef uint64_t fsblkcnt_t;
typedef uint64_t fsfilcnt_t;

/* despite glibc, Linux uses 32 bit dev_t */
typedef uint32_t dev_t;

typedef unsigned long aio_context_t;
typedef unsigned long nfds_t;

// should be a word, but we use 32 bits as bitops are signed 32 bit in LuaJIT at the moment
typedef int32_t fd_mask;

// again should be a long, and we have wrapped in a struct
// TODO ok to wrap Lua types but not syscall? https://github.com/justincormack/ljsyscall/issues/36
// TODO is this size right? check
struct cpu_set_t {
  int32_t val[1024 / (8 * sizeof (int32_t))];
};

typedef int mqd_t;
typedef int idtype_t; /* defined as enum */

struct timespec {
  time_t tv_sec;
  long   tv_nsec;
};

// misc
typedef void (*sighandler_t) (int);

// structs
struct timeval {
  long    tv_sec;         /* seconds */
  long    tv_usec;        /* microseconds */
};
struct itimerspec {
  struct timespec it_interval;
  struct timespec it_value;
};
struct itimerval {
  struct timeval it_interval;
  struct timeval it_value;
};
typedef struct __fsid_t {
  int __val[2];
} fsid_t;
//static const int UTSNAME_LENGTH = 65;
struct utsname {
  char sysname[65];
  char nodename[65];
  char release[65];
  char version[65];
  char machine[65];
  char domainname[65];
};
struct pollfd {
  int fd;
  short int events;
  short int revents;
};
typedef struct { /* based on Linux FD_SETSIZE = 1024, the kernel can do more, so can increase */
  fd_mask fds_bits[1024 / (sizeof (fd_mask) * 8)];
} fd_set;
struct ucred {
  pid_t pid;
  uid_t uid;
  gid_t gid;
};
struct rlimit64 {
  rlim64_t rlim_cur;
  rlim64_t rlim_max;
};
struct sysinfo {
  long uptime;
  unsigned long loads[3];
  unsigned long totalram;
  unsigned long freeram;
  unsigned long sharedram;
  unsigned long bufferram;
  unsigned long totalswap;
  unsigned long freeswap;
  unsigned short procs;
  unsigned short pad;
  unsigned long totalhigh;
  unsigned long freehigh;
  unsigned int mem_unit;
  char _f[20-2*sizeof(long)-sizeof(int)]; /* TODO ugh, remove calculation */
};
struct timex {
  unsigned int modes;
  long int offset;
  long int freq;
  long int maxerror;
  long int esterror;
  int status;
  long int constant;
  long int precision;
  long int tolerance;
  struct timeval time;
  long int tick;

  long int ppsfreq;
  long int jitter;
  int shift;
  long int stabil;
  long int jitcnt;
  long int calcnt;
  long int errcnt;
  long int stbcnt;

  int tai;

  int  :32; int  :32; int  :32; int  :32;
  int  :32; int  :32; int  :32; int  :32;
  int  :32; int  :32; int  :32;
};
typedef union sigval {
  int sival_int;
  void *sival_ptr;
} sigval_t;
struct cmsghdr {
  size_t cmsg_len;
  int cmsg_level;
  int cmsg_type;
  char cmsg_data[?];
};
struct msghdr {
  void *msg_name;
  socklen_t msg_namelen;
  struct iovec *msg_iov;
  size_t msg_iovlen;
  void *msg_control;
  size_t msg_controllen;
  int msg_flags;
};
struct mmsghdr {
  struct msghdr msg_hdr;
  unsigned int msg_len;
};
struct sockaddr {
  sa_family_t sa_family;
  char sa_data[14];
};
struct sockaddr_storage {
  sa_family_t ss_family;
  unsigned long int __ss_align;
  char __ss_padding[128 - 2 * sizeof(unsigned long int)]; /* total length 128 TODO no calculations */
};
struct sockaddr_in {
  sa_family_t    sin_family;
  in_port_t      sin_port;
  struct in_addr sin_addr;
  unsigned char  sin_zero[8];
};
struct sockaddr_in6 {
  sa_family_t    sin6_family;
  in_port_t sin6_port;
  uint32_t sin6_flowinfo;
  struct in6_addr sin6_addr;
  uint32_t sin6_scope_id;
};
struct sockaddr_un {
  sa_family_t sun_family;
  char        sun_path[108];
};
struct sockaddr_nl {
  sa_family_t     nl_family;
  unsigned short  nl_pad;
  uint32_t        nl_pid;
  uint32_t        nl_groups;
};
struct sockaddr_ll {
  unsigned short  sll_family;
  unsigned short  sll_protocol; /* __be16 */
  int             sll_ifindex;
  unsigned short  sll_hatype;
  unsigned char   sll_pkttype;
  unsigned char   sll_halen;
  unsigned char   sll_addr[8];
};
struct nlmsghdr {
  uint32_t           nlmsg_len;
  uint16_t           nlmsg_type;
  uint16_t           nlmsg_flags;
  uint32_t           nlmsg_seq;
  uint32_t           nlmsg_pid;
};
struct rtgenmsg {
  unsigned char rtgen_family;
};
struct ifinfomsg {
  unsigned char   ifi_family;
  unsigned char   __ifi_pad;
  unsigned short  ifi_type;
  int             ifi_index;
  unsigned        ifi_flags;
  unsigned        ifi_change;
};
struct rtattr {
  unsigned short  rta_len;
  unsigned short  rta_type;
};
struct nlmsgerr {
  int             error;
  struct nlmsghdr msg;
};
struct rtmsg {
  unsigned char rtm_family;
  unsigned char rtm_dst_len;
  unsigned char rtm_src_len;
  unsigned char rtm_tos;
  unsigned char rtm_table;
  unsigned char rtm_protocol;
  unsigned char rtm_scope;
  unsigned char rtm_type;
  unsigned int  rtm_flags;
};

static const int IFNAMSIZ = 16;

struct ifmap {
  unsigned long mem_start;
  unsigned long mem_end;
  unsigned short base_addr; 
  unsigned char irq;
  unsigned char dma;
  unsigned char port;
};
struct rtnl_link_stats {
  uint32_t rx_packets;
  uint32_t tx_packets;
  uint32_t rx_bytes;
  uint32_t tx_bytes;
  uint32_t rx_errors;
  uint32_t tx_errors;
  uint32_t rx_dropped;
  uint32_t tx_dropped;
  uint32_t multicast;
  uint32_t collisions;
  uint32_t rx_length_errors;
  uint32_t rx_over_errors;
  uint32_t rx_crc_errors;
  uint32_t rx_frame_errors;
  uint32_t rx_fifo_errors;
  uint32_t rx_missed_errors;
  uint32_t tx_aborted_errors;
  uint32_t tx_carrier_errors;
  uint32_t tx_fifo_errors;
  uint32_t tx_heartbeat_errors;
  uint32_t tx_window_errors;
  uint32_t rx_compressed;
  uint32_t tx_compressed;
};
struct ndmsg {
  uint8_t  ndm_family;
  uint8_t  ndm_pad1;
  uint16_t ndm_pad2;
  int32_t  ndm_ifindex;
  uint16_t ndm_state;
  uint8_t  ndm_flags;
  uint8_t  ndm_type;
};
struct nda_cacheinfo {
  uint32_t ndm_confirmed;
  uint32_t ndm_used;
  uint32_t ndm_updated;
  uint32_t ndm_refcnt;
};
struct ndt_stats {
  uint64_t ndts_allocs;
  uint64_t ndts_destroys;
  uint64_t ndts_hash_grows;
  uint64_t ndts_res_failed;
  uint64_t ndts_lookups;
  uint64_t ndts_hits;
  uint64_t ndts_rcv_probes_mcast;
  uint64_t ndts_rcv_probes_ucast;
  uint64_t ndts_periodic_gc_runs;
  uint64_t ndts_forced_gc_runs;
};
struct ndtmsg {
  uint8_t  ndtm_family;
  uint8_t  ndtm_pad1;
  uint16_t ndtm_pad2;
};
struct ndt_config {
  uint16_t ndtc_key_len;
  uint16_t ndtc_entry_size;
  uint32_t ndtc_entries;
  uint32_t ndtc_last_flush;
  uint32_t ndtc_last_rand;
  uint32_t ndtc_hash_rnd;
  uint32_t ndtc_hash_mask;
  uint32_t ndtc_hash_chain_gc;
  uint32_t ndtc_proxy_qlen;
};
typedef struct { 
  unsigned int clock_rate;
  unsigned int clock_type;
  unsigned short loopback;
} sync_serial_settings;
typedef struct { 
  unsigned int clock_rate;
  unsigned int clock_type;
  unsigned short loopback;
  unsigned int slot_map;
} te1_settings;
typedef struct {
  unsigned short encoding;
  unsigned short parity;
} raw_hdlc_proto;
typedef struct {
  unsigned int t391;
  unsigned int t392;
  unsigned int n391;
  unsigned int n392;
  unsigned int n393;
  unsigned short lmi;
  unsigned short dce;
} fr_proto;
typedef struct {
  unsigned int dlci;
} fr_proto_pvc;
typedef struct {
  unsigned int dlci;
  char master[IFNAMSIZ];
} fr_proto_pvc_info;
typedef struct {
  unsigned int interval;
  unsigned int timeout;
} cisco_proto;
struct if_settings {
  unsigned int type;
  unsigned int size;
  union {
    raw_hdlc_proto          *raw_hdlc;
    cisco_proto             *cisco;
    fr_proto                *fr;
    fr_proto_pvc            *fr_pvc;
    fr_proto_pvc_info       *fr_pvc_info;

    sync_serial_settings    *sync;
    te1_settings            *te1;
  } ifs_ifsu;
};
struct ifreq {
  union {
    char ifrn_name[IFNAMSIZ];
  } ifr_ifrn;
  union {
    struct  sockaddr ifru_addr;
    struct  sockaddr ifru_dstaddr;
    struct  sockaddr ifru_broadaddr;
    struct  sockaddr ifru_netmask;
    struct  sockaddr ifru_hwaddr;
    short   ifru_flags;
    int     ifru_ivalue;
    int     ifru_mtu;
    struct  ifmap ifru_map;
    char    ifru_slave[IFNAMSIZ];
    char    ifru_newname[IFNAMSIZ];
    void *  ifru_data;
    struct  if_settings ifru_settings;
  } ifr_ifru;
};
struct ifaddrmsg {
  uint8_t  ifa_family;
  uint8_t  ifa_prefixlen;
  uint8_t  ifa_flags;
  uint8_t  ifa_scope;
  uint32_t ifa_index;
};
struct ifa_cacheinfo {
  uint32_t ifa_prefered;
  uint32_t ifa_valid;
  uint32_t cstamp;
  uint32_t tstamp;
};
struct rta_cacheinfo {
  uint32_t rta_clntref;
  uint32_t rta_lastuse;
  uint32_t rta_expires;
  uint32_t rta_error;
  uint32_t rta_used;
  uint32_t rta_id;
  uint32_t rta_ts;
  uint32_t rta_tsage;
};
struct fdb_entry {
  uint8_t mac_addr[6];
  uint8_t port_no;
  uint8_t is_local;
  uint32_t ageing_timer_value;
  uint8_t port_hi;
  uint8_t pad0;
  uint16_t unused;
};
struct inotify_event {
  int wd;
  uint32_t mask;
  uint32_t cookie;
  uint32_t len;
  char name[?];
};
struct linux_dirent64 {
  uint64_t        d_ino;
  int64_t         d_off;
  unsigned short  d_reclen;
  unsigned char   d_type;
  char            d_name[0];
};
struct flock64 {
  short int l_type;
  short int l_whence;
  off_t l_start;
  off_t l_len;
  pid_t l_pid;
};
typedef union epoll_data {
  void *ptr;
  int fd;
  uint32_t u32;
  uint64_t u64;
} epoll_data_t;
struct signalfd_siginfo {
  uint32_t ssi_signo;
  int32_t ssi_errno;
  int32_t ssi_code;
  uint32_t ssi_pid;
  uint32_t ssi_uid;
  int32_t ssi_fd;
  uint32_t ssi_tid;
  uint32_t ssi_band;
  uint32_t ssi_overrun;
  uint32_t ssi_trapno;
  int32_t ssi_status;
  int32_t ssi_int;
  uint64_t ssi_ptr;
  uint64_t ssi_utime;
  uint64_t ssi_stime;
  uint64_t ssi_addr;
  uint8_t __pad[48];
};
struct io_event {
  uint64_t           data;
  uint64_t           obj;
  int64_t            res;
  int64_t            res2;
};
struct seccomp_data {
  int nr;
  uint32_t arch;
  uint64_t instruction_pointer;
  uint64_t args[6];
};
struct sock_filter {
  uint16_t   code;
  uint8_t    jt;
  uint8_t    jf;
  uint32_t   k;
};
struct bpf_insn {
  uint8_t code;   /* opcode */
  uint8_t dst_reg:4;  /* dest register */
  uint8_t src_reg:4;  /* source register */
  uint16_t off;   /* signed offset */
  uint32_t imm;   /* signed immediate constant */
};
struct sock_fprog {
  unsigned short len;
  struct sock_filter *filter;
};
union bpf_attr {
  struct {
    uint32_t   map_type;
    uint32_t   key_size;
    uint32_t   value_size;
    uint32_t   max_entries;
  };
  struct {
    uint32_t   map_fd;
    uint64_t   key __attribute__((aligned(8)));
    union {
      uint64_t value __attribute__((aligned(8)));
      uint64_t next_key __attribute__((aligned(8)));
    };
    uint64_t   flags;
  };
  struct {
    uint32_t   prog_type;
    uint32_t   insn_cnt;
    uint64_t   insns __attribute__((aligned(8)));
    uint64_t   license __attribute__((aligned(8)));
    uint32_t   log_level;
    uint32_t   log_size;
    uint64_t   log_buf __attribute__((aligned(8)));
    uint32_t   kern_version;
  };
  struct {
    uint64_t   pathname __attribute__((aligned(8)));
    uint32_t   bpf_fd;
  };
} __attribute__((aligned(8)));
struct perf_event_attr {
  uint32_t pe_type;
  uint32_t size;
  uint64_t pe_config;
  union {
    uint64_t sample_period;
    uint64_t sample_freq;
  };
  uint64_t pe_sample_type;
  uint64_t read_format;
  uint32_t disabled:1,
    inherit:1,
    pinned:1,
    exclusive:1,
    exclude_user:1,
    exclude_kernel:1,
    exclude_hv:1,
    exclude_idle:1,
    mmap:1,
    comm:1,
    freq:1,
    inherit_stat:1,
    enable_on_exec:1,
    task:1,
    watermark:1,
    precise_ip:2,
    mmap_data:1,
    sample_id_all:1,
    exclude_host:1,
    exclude_guest:1,
    exclude_callchain_kernel:1,
    exclude_callchain_user:1,
    mmap2:1,
    comm_exec:1,
    use_clockid:1,
    __reserved_1a:6;
    uint32_t __reserved_1b;
  union {
    uint32_t wakeup_events;
    uint32_t wakeup_watermark;
  };
  uint32_t bp_type;
  union {
    uint64_t bp_addr;
    uint64_t config1;
  };
  union {
    uint64_t bp_len;
    uint64_t config2;
  };
  uint64_t branch_sample_type;
  uint64_t sample_regs_user;
  uint32_t sample_stack_user;
  int32_t clockid;
  uint64_t sample_regs_intr;
  uint32_t aux_watermark;
  uint32_t __reserved_2;
};
struct perf_event_mmap_page {
  uint32_t version;
  uint32_t compat_version;
  uint32_t lock;
  uint32_t index;
  int64_t offset;
  uint64_t time_enabled;
  uint64_t time_running;
  union {
     uint64_t   capabilities;
     struct {
         uint32_t cap_bit0 : 1,
           cap_bit0_is_deprecated : 1,
           cap_user_rdpmc         : 1,
           cap_user_time          : 1,
           cap_user_time_zero     : 1;
     };
  };
  uint16_t pmc_width;
  uint16_t time_shift;
  uint32_t time_mult;
  uint64_t time_offset;
  uint64_t __reserved[120];
  volatile uint64_t data_head;
  volatile uint64_t data_tail;
  volatile uint64_t data_offset;
  volatile uint64_t data_size;
  uint64_t aux_head;
  uint64_t aux_tail;
  uint64_t aux_offset;
  uint64_t aux_size;
};
struct perf_event_header {
  uint32_t   type;
  uint16_t   misc;
  uint16_t   size;
};
struct mq_attr {
  long mq_flags, mq_maxmsg, mq_msgsize, mq_curmsgs, __unused[4];
};
struct termios2 {
    tcflag_t c_iflag;
    tcflag_t c_oflag;
    tcflag_t c_cflag;
    tcflag_t c_lflag;
    cc_t c_line;
    cc_t c_cc[19];
    speed_t c_ispeed;
    speed_t c_ospeed;
};
struct input_event {
    struct timeval time;
    uint16_t type;
    uint16_t code;
    int32_t value;
};
struct input_id {
    uint16_t bustype;
    uint16_t vendor;
    uint16_t product;
    uint16_t version;
};
struct input_absinfo {
    int32_t value;
    int32_t minimum;
    int32_t maximum;
    int32_t fuzz;
    int32_t flat;
    int32_t resolution;
};
struct input_keymap_entry {
    uint8_t  flags;
    uint8_t  len;
    uint16_t index;
    uint32_t keycode;
    uint8_t  scancode[32];
};
struct ff_replay {
    uint16_t length;
    uint16_t delay;
};
struct ff_trigger {
    uint16_t button;
    uint16_t interval;
};
struct ff_envelope {
    uint16_t attack_length;
    uint16_t attack_level;
    uint16_t fade_length;
    uint16_t fade_level;
};
struct ff_constant_effect {
    int16_t level;
    struct ff_envelope envelope;
};
struct ff_ramp_effect {
    int16_t start_level;
    int16_t end_level;
    struct ff_envelope envelope;
};
struct ff_condition_effect {
    uint16_t right_saturation;
    uint16_t left_saturation;
    int16_t right_coeff;
    int16_t left_coeff;
    uint16_t deadband;
    int16_t center;
};
struct ff_periodic_effect {
    uint16_t waveform;
    uint16_t period;
    int16_t magnitude;
    int16_t offset;
    uint16_t phase;
    struct ff_envelope envelope;
    uint32_t custom_len;
    int16_t *custom_data;
};
struct ff_rumble_effect {
    uint16_t strong_magnitude;
    uint16_t weak_magnitude;
};
struct ff_effect {
    uint16_t type;
    int16_t id;
    uint16_t direction;
    struct ff_trigger trigger;
    struct ff_replay replay;
    union {
        struct ff_constant_effect constant;
        struct ff_ramp_effect ramp;
        struct ff_periodic_effect periodic;
        struct ff_condition_effect condition[2];
        struct ff_rumble_effect rumble;
    } u;
};
typedef struct {
  int     val[2];
} kernel_fsid_t;
/* we define the underlying structs not the pointer typedefs for capabilities */
struct user_cap_header {
  uint32_t version;
  int pid;
};
struct user_cap_data {
  uint32_t effective;
  uint32_t permitted;
  uint32_t inheritable;
};
/* this are overall capabilities structs to put metatables on */
struct cap {
  uint32_t cap[2];
};
struct capabilities {
  uint32_t version;
  int pid;
  struct cap effective;
  struct cap permitted;
  struct cap inheritable;
};
struct xt_get_revision {
  char name[29];
  uint8_t revision;
};
struct vfs_cap_data {
  le32 magic_etc;
  struct {
    le32 permitted;    /* Little endian */
    le32 inheritable;  /* Little endian */
  } data[2];
};
typedef struct {
  void *ss_sp;
  int ss_flags;
  size_t ss_size;
} stack_t;
struct sched_param {
  int sched_priority;
  /* unused after here */
  int sched_ss_low_priority;
  struct timespec sched_ss_repl_period;
  struct timespec sched_ss_init_budget;
  int sched_ss_max_repl;
};
struct tun_filter {
  uint16_t flags;
  uint16_t count;
  uint8_t addr[0][6];
};
struct tun_pi {
  uint16_t flags;
  uint16_t proto; /* __be16 */
};
struct vhost_vring_state {
  unsigned int index;
  unsigned int num;
};
struct vhost_vring_file {
  unsigned int index;
  int fd;
};
struct vhost_vring_addr {
  unsigned int index;
  unsigned int flags;
  uint64_t desc_user_addr;
  uint64_t used_user_addr;
  uint64_t avail_user_addr;
  uint64_t log_guest_addr;
};
struct vhost_memory_region {
  uint64_t guest_phys_addr;
  uint64_t memory_size;
  uint64_t userspace_addr;
  uint64_t flags_padding;
};
struct vhost_memory {
  uint32_t nregions;
  uint32_t padding;
  struct vhost_memory_region regions[0];
};
struct rusage {
  struct timeval ru_utime;
  struct timeval ru_stime;
  long    ru_maxrss;
  long    ru_ixrss;
  long    ru_idrss;
  long    ru_isrss;
  long    ru_minflt;
  long    ru_majflt;
  long    ru_nswap;
  long    ru_inblock;
  long    ru_oublock;
  long    ru_msgsnd;
  long    ru_msgrcv;
  long    ru_nsignals;
  long    ru_nvcsw;
  long    ru_nivcsw;
};
]]

append(arch.nsig or [[
static const int _NSIG = 64;
]]
)

append(arch.sigset or [[
// again, should be a long
static const int _NSIG_BPW = 32;
typedef struct {
  int32_t sig[_NSIG / _NSIG_BPW];
} sigset_t;
]]
)

-- both Glibc and Musl have larger termios at least for some architectures; I believe this is correct for kernel
append(arch.termios or [[
struct termios {
  tcflag_t c_iflag;
  tcflag_t c_oflag;
  tcflag_t c_cflag;
  tcflag_t c_lflag;
  cc_t c_line;
  cc_t c_cc[19];
};
]]
)

-- Linux struct siginfo padding depends on architecture
if abi.abi64 then
append [[
static const int SI_MAX_SIZE = 128;
static const int SI_PAD_SIZE = (SI_MAX_SIZE / sizeof (int)) - 4;
]]
else
append [[
static const int SI_MAX_SIZE = 128;
static const int SI_PAD_SIZE = (SI_MAX_SIZE / sizeof (int)) - 3;
]]
end

append(arch.siginfo or [[
typedef struct siginfo {
  int si_signo;
  int si_errno;
  int si_code;

  union {
    int _pad[SI_PAD_SIZE];

    struct {
      pid_t si_pid;
      uid_t si_uid;
    } kill;

    struct {
      int si_tid;
      int si_overrun;
      sigval_t si_sigval;
    } timer;

    struct {
      pid_t si_pid;
      uid_t si_uid;
      sigval_t si_sigval;
    } rt;

    struct {
      pid_t si_pid;
      uid_t si_uid;
      int si_status;
      clock_t si_utime;
      clock_t si_stime;
    } sigchld;

    struct {
      void *si_addr;
    } sigfault;

    struct {
      long int si_band;
       int si_fd;
    } sigpoll;
  } _sifields;
} siginfo_t;
]]
)

-- this is the type used by the rt_sigaction syscall NB have renamed the fields to sa_
append(arch.sigaction or [[
struct k_sigaction {
  void (*sa_handler)(int);
  unsigned long sa_flags;
  void (*sa_restorer)(void);
  unsigned sa_mask[2];
};
]]
)

-- these could vary be arch but do not yet
append [[
static const int sigev_preamble_size = sizeof(int) * 2 + sizeof(sigval_t);
static const int sigev_max_size = 64;
static const int sigev_pad_size = (sigev_max_size - sigev_preamble_size) / sizeof(int);
typedef struct sigevent {
  sigval_t sigev_value;
  int sigev_signo;
  int sigev_notify;
  union {
    int _pad[sigev_pad_size];
    int _tid;
    struct {
      void (*_function)(sigval_t);
      void *_attribute;
    } _sigev_thread;
  } _sigev_un;
} sigevent_t;
]]

append(arch.ucontext) -- there is no default for ucontext and related types as very machine specific

if arch.statfs then append(arch.statfs)
else
-- Linux struct statfs/statfs64 depends on 64/32 bit
if abi.abi64 then
append [[
typedef long statfs_word;
]]
else
append [[
typedef uint32_t statfs_word;
]]
end

append [[
struct statfs64 {
  statfs_word f_type;
  statfs_word f_bsize;
  uint64_t f_blocks;
  uint64_t f_bfree;
  uint64_t f_bavail;
  uint64_t f_files;
  uint64_t f_ffree;
  kernel_fsid_t f_fsid;
  statfs_word f_namelen;
  statfs_word f_frsize;
  statfs_word f_flags;
  statfs_word f_spare[4];
};
]]
end

append(arch.stat)

-- epoll packed on x86_64 only (so same as x86)
append(arch.epoll or [[
struct epoll_event {
  uint32_t events;
  epoll_data_t data;
};
]]
)

-- endian dependent
if abi.le then
append [[
struct iocb {
  uint64_t   aio_data;
  uint32_t   aio_key, aio_reserved1;
  uint16_t   aio_lio_opcode;
  int16_t    aio_reqprio;
  uint32_t   aio_fildes;
  uint64_t   aio_buf;
  uint64_t   aio_nbytes;
  int64_t    aio_offset;
  uint64_t   aio_reserved2;
  uint32_t   aio_flags;
  uint32_t   aio_resfd;
};
]]
else
append [[
struct iocb {
  uint64_t   aio_data;
  uint32_t   aio_reserved1, aio_key;
  uint16_t   aio_lio_opcode;
  int16_t    aio_reqprio;
  uint32_t   aio_fildes;
  uint64_t   aio_buf;
  uint64_t   aio_nbytes;
  int64_t    aio_offset;
  uint64_t   aio_reserved2;
  uint32_t   aio_flags;
  uint32_t   aio_resfd;
};
]]
end

-- functions, minimal for Linux as mainly use syscall
append [[
long syscall(int number, ...);

int gettimeofday(struct timeval *tv, void *tz);
int clock_gettime(clockid_t clk_id, struct timespec *tp);

void exit(int status);
]]

ffi.cdef(table.concat(defs, ""))

