/*
 *   Copyright (c) 2010 - 2012
 *   Canonical Ltd. (All rights reserved)
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of version 2 of the GNU General Public
 *   License 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, contact Novell, Inc. or Canonical,
 *   Ltd.
 */
#include <iostream>
#include <stdlib.h>
#include <stdarg.h>

#include "parser.h"
#include "file_cache.h"

/* Policy versioning is determined by a combination of 3 values:
 * policy_version:     version of txt policy
 * parser_abi_version: version of abi revision of policy generated by parser
 * kernel_abi_version: version of abi revision for the kernel
 *
 * The version info is stored in a single 32 bit version field in the
 * header portion of each binary policy file.
 *
 * policy_version:
 *   a gross revision number indicating what features and semantics are
 *   expected by the text policy. This does not necessarily map directly
 *   to a feature set as a kernel may not have all the supported features
 *   patched/builtin.
 *
 *   policy_version is not supported by kernels that only support v5
 *   kernel abi, so it will not be written when creating policy for
 *   those kernels.
 *
 * kernel_abi_version:
 *   should be set to the highest version supported by both the parser and
 *   the kernel.
 *   This allows new kernels to detect old userspaces, and new parsers
 *   to support old kernels and policies semantics.
 *
 * parser_abi_version:
 *   should be bumped when a compiler error or some other event happens
 *   and policy cache needs to be forced to be recomputed, when the
 *   policy_version or kernel version has not changed.
 *
 *   parser_abi_version is not supported by kernels that only support
 *   v5 kernel abi so it will not be written when creating policy for those
 *   kernels.
 *
 * Default values set to v5 kernel abi before the different versioning
 * numbers where supported.
 */
uint32_t policy_version = 2;
uint32_t parser_abi_version = 2;
uint32_t kernel_abi_version = 5;

int force_complain = 0;
int perms_create = 0;                   /* perms contain create flag */
int net_af_max_override = -1;           /* use kernel to determine af_max */
int kernel_load = 1;
int kernel_supports_setload = 0;	/* kernel supports atomic set loads */
int features_supports_network = 0;	/* kernel supports network rules */
int features_supports_networkv8 = 0;	/* kernel supports 4.17 network rules */
int features_supports_unix = 0;		/* kernel supports unix socket rules */
int kernel_supports_policydb = 0;	/* kernel supports new policydb */
int features_supports_mount = 0;	/* kernel supports mount rules */
int features_supports_dbus = 0;		/* kernel supports dbus rules */
int kernel_supports_diff_encode = 0;	/* kernel supports diff_encode */
int features_supports_signal = 0;	/* kernel supports signal rules */
int features_supports_ptrace = 0;	/* kernel supports ptrace rules */
int features_supports_stacking = 0;	/* kernel supports stacking */
int features_supports_domain_xattr = 0;	/* x attachment cond */
int kernel_supports_oob = 0;		/* out of band transitions */
int conf_verbose = 0;
int conf_quiet = 0;
int names_only = 0;
int current_lineno = 1;
int option = OPTION_ADD;

dfaflags_t dfaflags = (dfaflags_t)(DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE | DFA_CONTROL_DIFF_ENCODE);
dfaflags_t warnflags = DEFAULT_WARNINGS;
dfaflags_t werrflags = 0;

const char *progname = __FILE__;
char *profile_ns = NULL;
char *profilename = NULL;
char *current_filename = NULL;

FILE *ofile = NULL;

IncludeCache_t *g_includecache;

#ifdef FORCE_READ_IMPLIES_EXEC
int read_implies_exec = 1;
#else
int read_implies_exec = 0;
#endif

void pwarnf(bool werr, const char *fmt, ...)
{
        va_list arg;
        char *newfmt;

        if (conf_quiet || names_only || option == OPTION_REMOVE)
                return;

        if (asprintf(&newfmt, _("%s from %s (%s%sline %d): %s"),
		     werr ? _("Warning converted to Error") : _("Warning"),
		     profilename ? profilename : "stdin",
		     current_filename ? current_filename : "",
		     current_filename ? " " : "",
		     current_lineno,
		     fmt) == -1)
                return;

        va_start(arg, fmt);
        vfprintf(stderr, newfmt, arg);
        va_end(arg);

        free(newfmt);

	if (werr) {
		fflush(stderr);
		exit(1);
	}
}

/* do we want to warn once/profile or just once per compile?? */
void common_warn_once(const char *name, const char *msg, const char **warned_name)
{
	if ((warnflags & WARN_RULE_NOT_ENFORCED) && *warned_name != name) {
		if (werrflags & WARN_RULE_NOT_ENFORCED)
			cerr << "Warning converted to Error";
		else
			cerr << "Warning";
		cerr << " from profile " << name << " (";
		if (current_filename)
			cerr << current_filename;
		else
			cerr << "stdin";
		cerr << "): " << msg << "\n";
		*warned_name = name;
	}

	if (werrflags & WARN_RULE_NOT_ENFORCED)
		exit(1);
}
