/*
 * Copyright (C) 2016 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef SNAP_CONFINE_MOUNTINFO_H
#define SNAP_CONFINE_MOUNTINFO_H

/**
 * Structure describing a single entry in /proc/self/sc_mountinfo
 **/
typedef struct sc_mountinfo_entry {
	/**
	 * The mount identifier of a given mount entry.
	 **/
	int mount_id;
	/**
	 * The parent mount identifier of a given mount entry.
	 **/
	int parent_id;
	unsigned dev_major, dev_minor;
	/**
	 * The root directory of a given mount entry.
	 **/
	char *root;
	/**
	 * The mount point of a given mount entry.
	 **/
	char *mount_dir;
	/**
	 * The mount options of a given mount entry.
	 **/
	char *mount_opts;
	/**
	 * Optional tagged data associated of a given mount entry.
	 *
	 * The return value is a string (possibly empty but never NULL) in the format
	 * tag[:value]. Known tags are:
	 *
	 * "shared:X":
	 * 		mount is shared in peer group X
	 * "master:X":
	 * 		mount is slave to peer group X
	 * "propagate_from:X"
	 * 		mount is slave and receives propagation from peer group X (*)
	 * "unbindable":
	 * 		mount is unbindable
	 *
	 * (*) X is the closest dominant peer group under the process's root.
	 * If X is the immediate master of the mount, or if there's no dominant peer
	 * group under the same root, then only the "master:X" field is present and not
	 * the "propagate_from:X" field.
	 **/
	char *optional_fields;
	/**
	 * The file system type of a given mount entry.
	 **/
	char *fs_type;
	/**
	 * The source of a given mount entry.
	 **/
	char *mount_source;
	/**
	 * The super block options of a given mount entry.
	 **/
	char *super_opts;

	struct sc_mountinfo_entry *next;

	// Buffer holding all of the text data above.
	//
	// The buffer must be the last element of the structure. It is allocated
	// along with the structure itself and does not need to be freed
	// separately.
	char line_buf[0];
} sc_mountinfo_entry;

/**
 * Structure describing entire /proc/self/sc_mountinfo file
 **/
typedef struct sc_mountinfo {
	sc_mountinfo_entry *first;
} sc_mountinfo;

/**
 * Parse a file in according to sc_mountinfo syntax.
 *
 * The argument can be used to parse an arbitrary file.  NULL can be used to
 * implicitly parse /proc/self/sc_mountinfo, that is the mount information
 * associated with the current process.
 **/
sc_mountinfo *sc_parse_mountinfo(const char *fname);

/**
 * Free a sc_mountinfo structure.
 *
 * This function is designed to be used with __attribute__((cleanup)) so it
 * takes a pointer to the freed object (which is also a pointer).
 **/
void sc_cleanup_mountinfo(sc_mountinfo ** ptr)
    __attribute__((nonnull(1)));

/**
 * Get the first sc_mountinfo entry.
 *
 * The returned value may be NULL if the parsed file contained no entries. The
 * returned value is bound to the lifecycle of the whole sc_mountinfo structure
 * and should not be freed explicitly.
 **/
sc_mountinfo_entry *sc_first_mountinfo_entry(sc_mountinfo * info)
    __attribute__((nonnull(1)));

/**
 * Get the next sc_mountinfo entry.
 *
 * The returned value is a pointer to the next sc_mountinfo entry or NULL if this
 * was the last entry. The returned value is bound to the lifecycle of the
 * whole sc_mountinfo structure and should not be freed explicitly.
 **/
sc_mountinfo_entry *sc_next_mountinfo_entry(sc_mountinfo_entry * entry)
    __attribute__((nonnull(1)));

#endif
