/*
 * mountP.h - private library header file
 *
 * Copyright (C) 2008-2012 Karel Zak <kzak@redhat.com>
 *
 * This file may be redistributed under the terms of the
 * GNU Lesser General Public License.
 */

#ifndef _LIBMOUNT_PRIVATE_H
#define _LIBMOUNT_PRIVATE_H

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>

#include "c.h"
#include "list.h"
#include "debug.h"
#include "libmount.h"

/*
 * Debug
 */
#define MNT_DEBUG_HELP		(1 << 0)
#define MNT_DEBUG_INIT		(1 << 1)
#define MNT_DEBUG_CACHE		(1 << 2)
#define MNT_DEBUG_OPTIONS	(1 << 3)
#define MNT_DEBUG_LOCKS		(1 << 4)
#define MNT_DEBUG_TAB		(1 << 5)
#define MNT_DEBUG_FS		(1 << 6)
#define MNT_DEBUG_UPDATE	(1 << 7)
#define MNT_DEBUG_UTILS		(1 << 8)
#define MNT_DEBUG_CXT		(1 << 9)
#define MNT_DEBUG_DIFF		(1 << 10)
#define MNT_DEBUG_MONITOR	(1 << 11)
#define MNT_DEBUG_BTRFS		(1 << 12)
#define MNT_DEBUG_LOOP		(1 << 13)

#define MNT_DEBUG_ALL		0xFFFF

UL_DEBUG_DECLARE_MASK(libmount);
#define DBG(m, x)	__UL_DBG(libmount, MNT_DEBUG_, m, x)
#define ON_DBG(m, x)	__UL_DBG_CALL(libmount, MNT_DEBUG_, m, x)
#define DBG_FLUSH	__UL_DBG_FLUSH(libmount, MNT_DEBUG_)

/*
 * NLS -- the library has to be independent on main program, so define
 * UL_TEXTDOMAIN_EXPLICIT before you include nls.h.
 *
 * Now we use util-linux.po (=PACKAGE), rather than maintain the texts
 * in the separate libmount.po file.
 */
#define LIBMOUNT_TEXTDOMAIN	PACKAGE
#define UL_TEXTDOMAIN_EXPLICIT	LIBMOUNT_TEXTDOMAIN
#include "nls.h"


/* extension for files in the directory */
#define MNT_MNTTABDIR_EXT	".fstab"

/* library private paths */
#define MNT_RUNTIME_TOPDIR	"/run"
#define MNT_RUNTIME_TOPDIR_OLD	"/dev"

#define MNT_PATH_UTAB		MNT_RUNTIME_TOPDIR "/mount/utab"
#define MNT_PATH_UTAB_OLD	MNT_RUNTIME_TOPDIR_OLD "/.mount/utab"

#define MNT_UTAB_HEADER	"# libmount utab file\n"

#ifdef TEST_PROGRAM
struct libmnt_test {
	const char	*name;
	int		(*body)(struct libmnt_test *ts, int argc, char *argv[]);
	const char	*usage;
};

/* test.c */
extern int mnt_run_test(struct libmnt_test *tests, int argc, char *argv[]);
#endif

/* utils.c */
extern int mnt_valid_tagname(const char *tagname);
extern int append_string(char **a, const char *b);

extern const char *mnt_statfs_get_fstype(struct statfs *vfs);
extern int is_file_empty(const char *name);

extern int mnt_is_readonly(const char *path)
			__attribute__((nonnull));

extern int mnt_parse_offset(const char *str, size_t len, uintmax_t *res);

extern int mnt_chdir_to_parent(const char *target, char **filename);

extern char *mnt_get_username(const uid_t uid);
extern int mnt_get_uid(const char *username, uid_t *uid);
extern int mnt_get_gid(const char *groupname, gid_t *gid);
extern int mnt_in_group(gid_t gid);

extern int mnt_open_uniq_filename(const char *filename, char **name);

extern int mnt_has_regular_utab(const char **utab, int *writable);
extern const char *mnt_get_utab_path(void);

extern int mnt_get_filesystems(char ***filesystems, const char *pattern);
extern void mnt_free_filesystems(char **filesystems);

extern char *mnt_get_kernel_cmdline_option(const char *name);
extern int mnt_guess_system_root(dev_t devno, struct libmnt_cache *cache, char **path);
extern int mnt_stat_mountpoint(const char *target, struct stat *st);

/* tab.c */
extern int is_mountinfo(struct libmnt_table *tb);
extern int mnt_table_set_parser_fltrcb(	struct libmnt_table *tb,
					int (*cb)(struct libmnt_fs *, void *),
					void *data);

extern int __mnt_table_parse_mtab(struct libmnt_table *tb,
					const char *filename,
					struct libmnt_table *u_tb);

extern struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
					struct libmnt_fs *fs,
					unsigned long mountflags,
					char **fsroot);

/*
 * Generic iterator
 */
struct libmnt_iter {
        struct list_head        *p;		/* current position */
        struct list_head        *head;		/* start position */
	int			direction;	/* MNT_ITER_{FOR,BACK}WARD */
};

#define IS_ITER_FORWARD(_i)	((_i)->direction == MNT_ITER_FORWARD)
#define IS_ITER_BACKWARD(_i)	((_i)->direction == MNT_ITER_BACKWARD)

#define MNT_ITER_INIT(itr, list) \
	do { \
		(itr)->p = IS_ITER_FORWARD(itr) ? \
				(list)->next : (list)->prev; \
		(itr)->head = (list); \
	} while(0)

#define MNT_ITER_ITERATE(itr, res, restype, member) \
	do { \
		res = list_entry((itr)->p, restype, member); \
		(itr)->p = IS_ITER_FORWARD(itr) ? \
				(itr)->p->next : (itr)->p->prev; \
	} while(0)


/*
 * This struct represents one entry in a mtab/fstab/mountinfo file.
 * (note that fstab[1] means the first column from fstab, and so on...)
 */
struct libmnt_fs {
	struct list_head ents;

	int		refcount;	/* reference counter */
	int		id;		/* mountinfo[1]: ID */
	int		parent;		/* mountinfo[2]: parent */
	dev_t		devno;		/* mountinfo[3]: st_dev */

	char		*bindsrc;	/* utab, full path from fstab[1] for bind mounts */

	char		*source;	/* fstab[1], mountinfo[10], swaps[1]:
                                         * source dev, file, dir or TAG */
	char		*tagname;	/* fstab[1]: tag name - "LABEL", "UUID", ..*/
	char		*tagval;	/*           tag value */

	char		*root;		/* mountinfo[4]: root of the mount within the FS */
	char		*target;	/* mountinfo[5], fstab[2]: mountpoint */
	char		*fstype;	/* mountinfo[9], fstab[3]: filesystem type */

	char		*optstr;	/* fstab[4], merged options */
	char		*vfs_optstr;	/* mountinfo[6]: fs-independent (VFS) options */
	char		*opt_fields;	/* mountinfo[7]: optional fields */
	char		*fs_optstr;	/* mountinfo[11]: fs-dependent options */
	char		*user_optstr;	/* userspace mount options */
	char		*attrs;		/* mount attributes */

	int		freq;		/* fstab[5]: dump frequency in days */
	int		passno;		/* fstab[6]: pass number on parallel fsck */

	/* /proc/swaps */
	char		*swaptype;	/* swaps[2]: device type (partition, file, ...) */
	off_t		size;		/* swaps[3]: swaparea size */
	off_t		usedsize;	/* swaps[4]: used size */
	int		priority;	/* swaps[5]: swap priority */

	int		flags;		/* MNT_FS_* flags */
	pid_t		tid;		/* /proc/<tid>/mountinfo otherwise zero */

	char		*comment;	/* fstab comment */

	void		*userdata;	/* library independent data */
};

/*
 * fs flags
 */
#define MNT_FS_PSEUDO	(1 << 1) /* pseudo filesystem */
#define MNT_FS_NET	(1 << 2) /* network filesystem */
#define MNT_FS_SWAP	(1 << 3) /* swap device */
#define MNT_FS_KERNEL	(1 << 4) /* data from /proc/{mounts,self/mountinfo} */
#define MNT_FS_MERGED	(1 << 5) /* already merged data from /run/mount/utab */

#define mnt_fs_is_regular(_f)	(!(mnt_fs_is_pseudofs(_f) \
				   || mnt_fs_is_netfs(_f) \
				   || mnt_fs_is_swaparea(_f)))

/*
 * mtab/fstab/mountinfo file
 */
struct libmnt_table {
	int		fmt;		/* MNT_FMT_* file format */
	int		nents;		/* number of entries */
	int		refcount;	/* reference counter */
	int		comms;		/* enable/disable comment parsing */
	char		*comm_intro;	/* First comment in file */
	char		*comm_tail;	/* Last comment in file */

	struct libmnt_cache *cache;		/* canonicalized paths/tags cache */

        int		(*errcb)(struct libmnt_table *tb,
				 const char *filename, int line);

	int		(*fltrcb)(struct libmnt_fs *fs, void *data);
	void		*fltrcb_data;


	struct list_head	ents;	/* list of entries (libmnt_fs) */
	void		*userdata;
};

extern struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt);

/*
 * Tab file format
 */
enum {
	MNT_FMT_GUESS,
	MNT_FMT_FSTAB,			/* /etc/{fs,m}tab */
	MNT_FMT_MTAB = MNT_FMT_FSTAB,	/* alias */
	MNT_FMT_MOUNTINFO,		/* /proc/#/mountinfo */
	MNT_FMT_UTAB,			/* /run/mount/utab */
	MNT_FMT_SWAPS			/* /proc/swaps */
};

/*
 * Additional mounts
 */
struct libmnt_addmount {
	unsigned long mountflags;

	struct list_head	mounts;
};

/*
 * Mount context -- high-level API
 */
struct libmnt_context
{
	int	action;		/* MNT_ACT_{MOUNT,UMOUNT} */
	int	restricted;	/* root or not? */

	char	*fstype_pattern;	/* for mnt_match_fstype() */
	char	*optstr_pattern;	/* for mnt_match_options() */

	struct libmnt_fs *fs;		/* filesystem description (type, mountpoint, device, ...) */

	struct libmnt_table *fstab;	/* fstab (or mtab for some remounts) entries */
	struct libmnt_table *mtab;	/* mtab entries */
	struct libmnt_table *utab;	/* rarely used by umount only */

	int	(*table_errcb)(struct libmnt_table *tb,	/* callback for libmnt_table structs */
			 const char *filename, int line);

	int	(*table_fltrcb)(struct libmnt_fs *fs, void *data);	/* callback for libmnt_table structs */
	void	*table_fltrcb_data;

	char	*(*pwd_get_cb)(struct libmnt_context *);		/* get encryption password */
	void	(*pwd_release_cb)(struct libmnt_context *, char *);	/* release password */

	int	optsmode;	/* fstab optstr mode MNT_OPTSMODE_{AUTO,FORCE,IGNORE} */
	int	loopdev_fd;	/* open loopdev */

	unsigned long	mountflags;	/* final mount(2) flags */
	const void	*mountdata;	/* final mount(2) data, string or binary data */

	unsigned long	user_mountflags;	/* MNT_MS_* (loop=, user=, ...) */

	struct list_head	addmounts;	/* additional mounts */

	struct libmnt_cache	*cache;	/* paths cache */
	struct libmnt_lock	*lock;	/* mtab lock */
	struct libmnt_update	*update;/* mtab/utab update */

	const char	*mtab_path; /* path to mtab */
	int		mtab_writable; /* is mtab writable */

	const char	*utab_path; /* path to utab */
	int		utab_writable; /* is utab writable */

	int	flags;		/* private context flags */

	char	*helper;	/* name of the used /sbin/[u]mount.<type> helper */
	int	helper_status;	/* helper wait(2) status */
	int	helper_exec_status; /* 1: not called yet, 0: success, <0: -errno */

	char	*orig_user;	/* original (non-fixed) user= option */

	pid_t	*children;	/* "mount -a --fork" PIDs */
	int	nchildren;	/* number of children */
	pid_t	pid;		/* 0=parent; PID=child */


	int	syscall_status;	/* 1: not called yet, 0: success, <0: -errno */

	unsigned int	enabled_textdomain : 1;		/* bindtextdomain() called */
};

/* flags */
#define MNT_FL_NOMTAB		(1 << 1)
#define MNT_FL_FAKE		(1 << 2)
#define MNT_FL_SLOPPY		(1 << 3)
#define MNT_FL_VERBOSE		(1 << 4)
#define MNT_FL_NOHELPERS	(1 << 5)
#define MNT_FL_LOOPDEL		(1 << 6)
#define MNT_FL_LAZY		(1 << 7)
#define MNT_FL_FORCE		(1 << 8)
#define MNT_FL_NOCANONICALIZE	(1 << 9)
#define MNT_FL_RDONLY_UMOUNT	(1 << 11)	/* remount,ro after EBUSY umount(2) */
#define MNT_FL_FORK		(1 << 12)
#define MNT_FL_NOSWAPMATCH	(1 << 13)
#define MNT_FL_RWONLY_MOUNT	(1 << 14)	/* explicit mount -w; never try read-only  */

#define MNT_FL_MOUNTDATA	(1 << 20)
#define MNT_FL_TAB_APPLIED	(1 << 21)	/* mtab/fstab merged to cxt->fs */
#define MNT_FL_MOUNTFLAGS_MERGED (1 << 22)	/* MS_* flags was read from optstr */
#define MNT_FL_SAVED_USER	(1 << 23)
#define MNT_FL_PREPARED		(1 << 24)
#define MNT_FL_HELPER		(1 << 25)	/* [u]mount.<type> */
#define MNT_FL_LOOPDEV_READY	(1 << 26)	/* /dev/loop<N> initialized by the library */
#define MNT_FL_MOUNTOPTS_FIXED  (1 << 27)
#define MNT_FL_TABPATHS_CHECKED	(1 << 28)
#define MNT_FL_FORCED_RDONLY	(1 << 29)	/* mounted read-only on write-protected device */

/* default flags */
#define MNT_FL_DEFAULT		0

/* lock.c */
extern int mnt_lock_use_simplelock(struct libmnt_lock *ml, int enable);

/* optmap.c */
extern const struct libmnt_optmap *mnt_optmap_get_entry(
			     struct libmnt_optmap const **maps,
                             int nmaps,
			     const char *name,
                             size_t namelen,
			     const struct libmnt_optmap **mapent);

/* optstr.c */
extern int mnt_optstr_remove_option_at(char **optstr, char *begin, char *end);
extern int mnt_optstr_fix_gid(char **optstr, char *value, size_t valsz, char **next);
extern int mnt_optstr_fix_uid(char **optstr, char *value, size_t valsz, char **next);
extern int mnt_optstr_fix_secontext(char **optstr, char *value, size_t valsz, char **next);
extern int mnt_optstr_fix_user(char **optstr);

/* fs.c */
extern struct libmnt_fs *mnt_copy_mtab_fs(const struct libmnt_fs *fs)
			__attribute__((nonnull));
extern int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
			__attribute__((nonnull(1)));
extern int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
			__attribute__((nonnull(1)));

/* context.c */
extern int mnt_context_mtab_writable(struct libmnt_context *cxt);
extern int mnt_context_utab_writable(struct libmnt_context *cxt);
extern const char *mnt_context_get_writable_tabpath(struct libmnt_context *cxt);

extern int mnt_context_get_mtab_for_target(struct libmnt_context *cxt,
				    struct libmnt_table **mtab, const char *tgt);

extern int mnt_context_prepare_srcpath(struct libmnt_context *cxt);
extern int mnt_context_prepare_target(struct libmnt_context *cxt);
extern int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type);
extern int mnt_context_guess_fstype(struct libmnt_context *cxt);
extern int mnt_context_prepare_helper(struct libmnt_context *cxt,
				      const char *name, const char *type);
extern int mnt_context_prepare_update(struct libmnt_context *cxt);
extern int mnt_context_merge_mflags(struct libmnt_context *cxt);
extern int mnt_context_update_tabs(struct libmnt_context *cxt);

extern int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg);
extern int mnt_context_mount_setopt(struct libmnt_context *cxt, int c, char *arg);

extern int mnt_context_is_loopdev(struct libmnt_context *cxt)
			__attribute__((nonnull));

extern int mnt_context_propagation_only(struct libmnt_context *cxt)
			__attribute__((nonnull));

extern struct libmnt_addmount *mnt_new_addmount(void);
extern void mnt_free_addmount(struct libmnt_addmount *ad);

extern int mnt_context_setup_loopdev(struct libmnt_context *cxt);
extern int mnt_context_delete_loopdev(struct libmnt_context *cxt);
extern int mnt_context_clear_loopdev(struct libmnt_context *cxt);

extern int mnt_fork_context(struct libmnt_context *cxt);

extern int mnt_context_set_tabfilter(struct libmnt_context *cxt,
				     int (*fltr)(struct libmnt_fs *, void *),
				     void *data);

extern int mnt_context_get_generic_excode(int rc, char *buf, size_t bufsz, char *fmt, ...);
extern int mnt_context_get_mount_excode(struct libmnt_context *cxt, int mntrc, char *buf, size_t bufsz);
extern int mnt_context_get_umount_excode(struct libmnt_context *cxt, int mntrc, char *buf, size_t bufsz);

/* tab_update.c */
extern int mnt_update_set_filename(struct libmnt_update *upd,
				   const char *filename, int userspace_only);
extern int mnt_update_already_done(struct libmnt_update *upd,
				   struct libmnt_lock *lc);

#if __linux__
/* btrfs.c */
extern uint64_t btrfs_get_default_subvol_id(const char *path);
#endif

#endif /* _LIBMOUNT_PRIVATE_H */
