/**
@file
@brief    File system call hooks table and definitions
@details  Copyright (c) 2017-2022 Acronis International GmbH
@author   Mikhail Molchanov (Mikhail.Molchanov@acronis.com)
@since    $Id: $
*/

#pragma once

#include "syscall_utils.h"

#include <linux/compat.h>	// for compat_ptr() and compat types
#include <linux/uio.h>		// for 'struct iovec'

#define DEFINE_SYSCALL_TYPE(...) \
	DEFINE_SYSCALL_HOOK_TYPE(__VA_ARGS__); \
	DEFINE_SYSCALL_ORIG_TYPE(__VA_ARGS__)

// typedefs of 'ordinary' syscall hooks:
DEFINE_SYSCALL_TYPE(sys, creat, 2, const char __user *, pathname, umode_t, mode);

DEFINE_SYSCALL_TYPE(sys, open, 3, const char __user *, filename, int, flags, umode_t, mode);
DEFINE_SYSCALL_TYPE(sys, openat, 4, int, dfd, const char __user *, filename, int, flags, umode_t, mode);

DEFINE_SYSCALL_TYPE(sys, close, 1, unsigned int, fd);

DEFINE_SYSCALL_TYPE(sys, read, 3, unsigned int, fd, char __user *, buf, size_t, count);
DEFINE_SYSCALL_TYPE(sys, readv, 3, unsigned long, fd, const struct iovec __user *, vec,
						 unsigned long, vlen);
DEFINE_SYSCALL_TYPE(sys, pread64, 4, unsigned int, fd, char __user *, buf,
						 size_t, count, loff_t, pos);
DEFINE_SYSCALL_TYPE(sys, preadv, 5, unsigned long, fd, const struct iovec __user *, vec,
						 unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h);
DEFINE_SYSCALL_TYPE(sys, preadv2, 6, unsigned long, fd, const struct iovec __user *, vec,
						 unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h, int, flags);

DEFINE_SYSCALL_TYPE(sys, write, 3, unsigned int, fd, const char __user *, buf, size_t, count);
DEFINE_SYSCALL_TYPE(sys, pwrite64, 4, unsigned int, fd, const char __user *, buf, size_t, count, loff_t, pos);
// FIXME: all '*writev*()' funcs have 'unsigned long fd', not 'unsigned int fd'
DEFINE_SYSCALL_TYPE(sys, writev, 3, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen);
DEFINE_SYSCALL_TYPE(sys, pwritev, 5, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen,
					      unsigned long, pos_l, unsigned long, pos_h);
DEFINE_SYSCALL_TYPE(sys, pwritev2, 6, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen,
					       unsigned long, pos_l, unsigned long, pos_h,
					       int, flags);

DEFINE_SYSCALL_TYPE(sys, rename, 2, const char __user *, oldname, const char __user *, newname);
DEFINE_SYSCALL_TYPE(sys, renameat, 4, int, olddfd, const char __user *, oldname,
					       int, newdfd, const char __user *, newname);
DEFINE_SYSCALL_TYPE(sys, renameat2, 5, int, olddfd, const char __user *,oldname,
						int, newdfd, const char __user *,newname,
						unsigned int, flags);

DEFINE_SYSCALL_TYPE(sys, unlink, 1, const char __user *, pathname);
DEFINE_SYSCALL_TYPE(sys, unlinkat, 3, int, dfd, const char __user *, pathname, int, flag);

// Note: many 'ia32' hooks have the same 'type' as 'x86_64' hooks
#define DEFINE_SYSCALL_HOOK_TYPE_ALIAS(abi1, abi2, tag) \
	typedef SYSCALL_HOOK_TYPE_NAME(abi2, tag) SYSCALL_HOOK_TYPE_NAME(abi1, tag)
#define DEFINE_SYSCALL_ORIG_TYPE_ALIAS(abi1, abi2, tag) \
	typedef SYSCALL_ORIG_TYPE_NAME(abi2, tag) SYSCALL_ORIG_TYPE_NAME(abi1, tag)

#define DEFINE_SYSCALL_TYPE_ALIAS(...) \
	DEFINE_SYSCALL_HOOK_TYPE_ALIAS(__VA_ARGS__);  \
	DEFINE_SYSCALL_ORIG_TYPE_ALIAS(__VA_ARGS__)

DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, creat);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, open);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, openat);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, close);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, write);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, rename);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, renameat);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, renameat2);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, unlink);
DEFINE_SYSCALL_TYPE_ALIAS(ia32_sys, sys, unlinkat);

#define DEFINE_COMPAT_SYSCALL_TYPE(...) \
	DEFINE_COMPAT_SYSCALL_HOOK_TYPE(__VA_ARGS__); \
	DEFINE_COMPAT_SYSCALL_ORIG_TYPE(__VA_ARGS__)

// typedefs of 'compat' syscall hooks (no need for 'ia32' here, cause their typedefs are the same as 'ordinary' ones):
// 'sys32_pread()' in Linux source code
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, pread64, 5, unsigned int, fd, const char __user *, ubuf, u32, count,
								u32, poslo, u32, poshi);
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, readv, 3,
								compat_ulong_t, fd,
								const struct compat_iovec __user *, cvec,
								compat_ulong_t, cvlen);
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, preadv, 5,
								compat_ulong_t, fd,
								const struct compat_iovec __user *, cvec,
								compat_ulong_t, cvlen,
								u32, pos_low,
								u32, pos_high);
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, preadv2, 6,
								compat_ulong_t, fd,
								const struct compat_iovec __user *, cvec,
								compat_ulong_t, cvlen,
								u32, pos_low,
								u32, pos_high,
								int, flags);

// typedefs of 'compat' syscall hooks (no need for 'ia32' here, cause their typedefs are the same as 'ordinary' ones):
// 'sys32_pwrite()' in Linux source code
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, pwrite64, 5, unsigned int, fd, const char __user *, ubuf, u32, count,
						u32, poslo, u32, poshi);
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, writev, 3, compat_ulong_t, fd, const struct compat_iovec __user *, vec, compat_ulong_t, vlen);
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, pwritev, 5, compat_ulong_t, fd, const struct compat_iovec __user *, vec, compat_ulong_t, vlen,
						u32, pos_low, u32, pos_high);
DEFINE_COMPAT_SYSCALL_TYPE(compat_sys, pwritev2, 6, compat_ulong_t, fd, const struct compat_iovec __user *, vec, compat_ulong_t, vlen,
						      u32, pos_low, u32, pos_high,
						      int, flags);

// declarations of 'ordinary' syscall hooks:
DECLARE_SYSCALL_HOOK(sys, creat, 2, const char __user *, pathname, umode_t, mode);

DECLARE_SYSCALL_HOOK(sys, open, 3, const char __user *, filename, int, flags, umode_t, mode);

DECLARE_SYSCALL_HOOK(sys, openat, 4, int, dfd, const char __user *, filename, int, flags, umode_t, mode);

DECLARE_SYSCALL_HOOK(sys, close, 1, unsigned int, fd);

DECLARE_SYSCALL_HOOK(sys, read, 3, unsigned int, fd, char __user *, buf, size_t, count);
DECLARE_SYSCALL_HOOK(sys, pread64, 4, unsigned int, fd, char __user *, buf,
					 size_t, count, loff_t, pos);
DECLARE_SYSCALL_HOOK(sys, readv, 3, unsigned long, fd, const struct iovec __user *, vec,
					 unsigned long, vlen);
DECLARE_SYSCALL_HOOK(sys, preadv, 5, unsigned long, fd, const struct iovec __user *, vec,
					 unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h);
DECLARE_SYSCALL_HOOK(sys, preadv2, 6, unsigned long, fd, const struct iovec __user *, vec,
					 unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h, int, flags);

DECLARE_SYSCALL_HOOK(sys, write, 3, unsigned int, fd, const char __user *, buf, size_t, count);
DECLARE_SYSCALL_HOOK(sys, pwrite64, 4, unsigned int, fd, const char __user *, buf, size_t, count, loff_t, pos);
DECLARE_SYSCALL_HOOK(sys, writev, 3, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen);
DECLARE_SYSCALL_HOOK(sys, pwritev, 5, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h);
DECLARE_SYSCALL_HOOK(sys, pwritev2, 6, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h, int, flags);

DECLARE_SYSCALL_HOOK(sys, rename, 2, const char __user *, oldname, const char __user *, newname);
DECLARE_SYSCALL_HOOK(sys, renameat, 4, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname);
DECLARE_SYSCALL_HOOK(sys, renameat2, 5, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, unsigned int, flags);

DECLARE_SYSCALL_HOOK(sys, unlink, 1, const char __user *, pathname);
DECLARE_SYSCALL_HOOK(sys, unlinkat, 3, int, dfd, const char __user *, pathname, int, flag);


// declarations of 'ia32' and 'compat' syscall hooks:
DECLARE_SYSCALL_HOOK(ia32_sys, creat, 2, const char __user *, pathname, umode_t, mode);

DECLARE_SYSCALL_HOOK(ia32_sys, open, 3, const char __user *, filename, int, flags, umode_t, mode);
DECLARE_SYSCALL_HOOK(ia32_sys, openat, 4, int, dfd, const char __user *, filename, int, flags, umode_t, mode);

DECLARE_SYSCALL_HOOK(ia32_sys, close, 1, unsigned int, fd);

DECLARE_SYSCALL_HOOK(ia32_sys, read, 3, unsigned int, fd, char __user *, buf, size_t, count);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, readv, 3,
							compat_ulong_t, fd,
							const struct compat_iovec __user *, cvec,
							compat_ulong_t, cvlen);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, pread64, 5, unsigned int, fd, const char __user *, ubuf, u32, count,
							u32, poslo, u32, poshi);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, preadv, 5,
							compat_ulong_t, fd,
							const struct compat_iovec __user *, cvec,
							compat_ulong_t, cvlen,
							u32, pos_low,
							u32, pos_high);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, preadv2, 6,
							compat_ulong_t, fd,
							const struct compat_iovec __user *, cvec,
							compat_ulong_t, cvlen,
							u32, pos_low,
							u32, pos_high,
							int, flags);

DECLARE_SYSCALL_HOOK(ia32_sys, write, 3, unsigned int, fd, const char __user *, buf, size_t, count);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, pwrite64, 5, unsigned int, fd, const char __user *, ubuf, u32, count,  u32, poslo, u32, poshi);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, writev, 3, compat_ulong_t, fd, const struct compat_iovec __user *, vec, compat_ulong_t, vlen);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, pwritev, 5, compat_ulong_t, fd, const struct compat_iovec __user *, vec, compat_ulong_t, vlen, u32, pos_low, u32, pos_high);
DECLARE_COMPAT_SYSCALL_HOOK(compat_sys, pwritev2, 6, compat_ulong_t, fd, const struct compat_iovec __user *, vec, compat_ulong_t, vlen, u32, pos_low, u32, pos_high, int, flags);

DECLARE_SYSCALL_HOOK(ia32_sys, rename, 2, const char __user *, oldname, const char __user *, newname);
DECLARE_SYSCALL_HOOK(ia32_sys, renameat, 4, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname);
DECLARE_SYSCALL_HOOK(ia32_sys, renameat2, 5, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, unsigned int, flags);

DECLARE_SYSCALL_HOOK(ia32_sys, unlink, 1, const char __user *, pathname);
DECLARE_SYSCALL_HOOK(ia32_sys, unlinkat, 3, int, dfd, const char __user *, pathname, int, flag);
