#ifndef __CR_MOUNT_H__
#define __CR_MOUNT_H__

#include <sys/types.h>

#include "common/list.h"

struct proc_mountinfo;
struct pstree_item;
struct fstype;
struct ns_id;

#define MOUNT_INVALID_DEV (0)

#define MNT_UNREACHABLE INT_MIN

/*
 * We have remounted these mount writable temporary, and we
 * should return it back to readonly at the end of file restore.
 */
#define REMOUNTED_RW 1
/*
 * We have remounted these mount writable in service mount namespace,
 * thus we shouldn't return it back to readonly, as service mntns
 * will be destroyed anyway.
 */
#define REMOUNTED_RW_SERVICE 2

struct mount_info {
	int mnt_id;
	int parent_mnt_id;
	unsigned int s_dev;
	unsigned int s_dev_rt;
	char *root;
	/*
	 * During dump mountpoint contains path with dot at the
	 * beginning. It allows to use openat, statat, etc without
	 * creating a temporary copy of the path.
	 *
	 * On restore mountpoint is prepended with so called ns
	 * root path -- it's a place in fs where the namespace
	 * mount tree is constructed. Check mnt_roots for details.
	 * The ns_mountpoint contains path w/o this prefix.
	 */
	char *mountpoint;
	char *ns_mountpoint;
	int fd;
	unsigned flags;
	unsigned sb_flags;
	int master_id;
	int shared_id;
	struct fstype *fstype;
	char *source;
	char *options;
	char *fsname;
	union {
		bool mounted;
		bool dumped;
	};
	bool need_plugin;
	bool is_ns_root;
	bool deleted;
	struct mount_info *next;
	struct ns_id *nsid;

	char *external;
	bool internal_sharing;

	/* tree linkage */
	struct mount_info *parent;
	struct mount_info *bind;
	struct list_head children;
	struct list_head siblings;

	struct list_head mnt_bind; /* circular list of derivatives of one real mount */
	struct list_head mnt_share; /* circular list of shared mounts */
	struct list_head mnt_slave_list; /* list of slave mounts */
	struct list_head mnt_slave; /* slave list entry */
	struct mount_info *mnt_master; /* slave is on master->mnt_slave_list */
	struct list_head mnt_propagate; /* circular list of mounts which propagate from each other */
	struct list_head mnt_notprop; /* temporary list used in can_mount_now */
	struct list_head mnt_unbindable; /* list of mounts with delayed unbindable */

	struct list_head postpone;

	int is_overmounted;
	int remounted_rw;

	void *private; /* associated filesystem data */
};

extern struct mount_info *mntinfo;
extern struct ns_desc mnt_ns_desc;
#ifdef CONFIG_BINFMT_MISC_VIRTUALIZED
extern int collect_binfmt_misc(void);
#else
static inline int collect_binfmt_misc(void)
{
	return 0;
}
#endif

extern struct mount_info *mnt_entry_alloc(void);
extern void mnt_entry_free(struct mount_info *mi);

extern int __mntns_get_root_fd(pid_t pid);
extern int mntns_get_root_fd(struct ns_id *ns);
extern int mntns_get_root_by_mnt_id(int mnt_id);
extern struct ns_id *lookup_nsid_by_mnt_id(int mnt_id);

extern int open_mount(unsigned int s_dev);
extern int __open_mountpoint(struct mount_info *pm, int mnt_fd);
extern int mnt_is_dir(struct mount_info *pm);
extern int open_mountpoint(struct mount_info *pm);

extern struct mount_info *collect_mntinfo(struct ns_id *ns, bool for_dump);
extern int prepare_mnt_ns(void);

extern int pivot_root(const char *new_root, const char *put_old);

extern struct mount_info *lookup_overlayfs(char *rpath, unsigned int s_dev, unsigned int st_ino, unsigned int mnt_id);
extern struct mount_info *lookup_mnt_id(unsigned int id);
extern struct mount_info *lookup_mnt_sdev(unsigned int s_dev);

extern dev_t phys_stat_resolve_dev(struct ns_id *, dev_t st_dev, const char *path);
extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, struct ns_id *, const char *path);

extern int restore_task_mnt_ns(struct pstree_item *current);
extern void fini_restore_mntns(void);
extern int depopulate_roots_yard(int mntns_root, bool clean_remaps);

extern int rst_get_mnt_root(int mnt_id, char *path, int plen);
extern int ext_mount_add(char *key, char *val);
extern int ext_mount_parse_auto(char *key);
extern int mntns_maybe_create_roots(void);
extern int read_mnt_ns_img(void);
extern void cleanup_mnt_ns(void);
extern void clean_cr_time_mounts(void);

extern bool add_skip_mount(const char *mountpoint);
struct ns_id;
extern struct mount_info *parse_mountinfo(pid_t pid, struct ns_id *nsid, bool for_dump);

extern int check_mnt_id(void);

extern int remount_readonly_mounts(void);
extern int try_remount_writable(struct mount_info *mi, bool ns);
extern bool mnt_is_overmounted(struct mount_info *mi);

#endif /* __CR_MOUNT_H__ */
