#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h> // fchmod
#include <sandbox.h>
#include "sandbox.h" // My sandbox.h

typedef int bool;
#include <dlfcn.h>

void usage(void)
{
	
	fprintf(stderr, "Usage: sandbox-exec [options] command [args]\nOptions:\n  -f profile-file     Read profile from file.\n  -n profile-name     Use pre-defined profile.\n  -p profile-string   Specify profile on the command line.\n  -D key=value        Define a profile parameter.\n -t trace_file    Trace operations to trace_file\n Exactly one of -f, -n, -p must be specified.\n");

	exit(0x40);

} // usage


int debug = 0;
#define dprintf if (debug) printf

int main (int argc, char **argv)
{

	debug = (getenv ("JDEBUG") != NULL);
	// This is as close as possible to the decompilation of OS X's (10.11.4) sandbox-exec
	// including calling sandbox_create_params() before processing arguments. 

	sbProfile_t *compiled_profile;

	char *err = NULL;

	sbParams_t *params=sandbox_create_params();

	if (!params) { fprintf(stderr,"Can't create params!\n"); exit(1);}

	if (argc < 2) { usage(); }



	int opt;

	char *profile = NULL;
	int cmd = 0;
	char *profileName = NULL;
	char *profileString = NULL;
	char *tracePath = NULL;

	while ((opt = getopt(argc,argv,"D:c:de:f:n:p:t:")) > -1)
	  {
		switch (opt)
		{
			case 'f':  profile = optarg; break;
			case 'n':  profileName = optarg; break;
			case 'p':  profileString = optarg; break;
			case 't':  tracePath = optarg; break;
		
			default: usage();
	
			
		
		}

	  }

	cmd = optind;
	
	if (tracePath && profileName)
	{
		fprintf(stderr, "tracing isn't implemented for named profiles; use -f or -p to specify a profile\n");		
		exit(0x40);
	}

	//compiled_profile = sandbox_compile_entitlements ("no-internet", params, &err);


	if (profile) compiled_profile = sandbox_compile_file (profile, params, &err);

	// The built-in profiles:
	// ----------------------
	// kSBXProfileNoInternet (no-internet)
	// kSBXProfileNoWriteExceptTemporary (no-write-except-temporary)
	// kSBXProfileNoWrite         (no-write)
	// kSBXProfileNoNetwork       (no-network)
	// kSBXProfilePureComputation (pure-computation)

	if (profileName) compiled_profile = sandbox_compile_named (profileName, params, &err);
	if (profileString) compiled_profile = sandbox_compile_string (profileString, params, &err);

	//sandbox_set_param (params, "x", "y");
	if(!compiled_profile) { fprintf(stderr, "No compiled profile. Error: %s\n", err); exit(2); } 


	int dump= 1;
	if (dump && compiled_profile->blob)
	{
	fprintf(stderr,"Profile: %s, Blob: %p Length: %d\n",
			(compiled_profile->name? compiled_profile->name : "(custom)" ), 
                         compiled_profile->blob, compiled_profile->len);
	int fd = open("/tmp/out.bin", O_WRONLY | O_TRUNC| O_CREAT);
	fchmod (fd, 0666);
	write(fd, compiled_profile->blob, compiled_profile->len);
	fprintf(stderr,"dumped compiled profile to /tmp/out.bin\n");
	}

	int flags = 0;
	int rc = 0;
	if (tracePath) { 
#ifdef SB459
		
		rc = sandbox_set_trace_path(compiled_profile,tracePath); 
#else
		void *sblibhandle = dlopen ("libsandbox.dylib", RTLD_GLOBAL);

		typedef int sstp(void *, char *);
		sstp * sandbox_set_trace_path = dlsym (sblibhandle, "sandbox_set_trace_path");

		if (!sandbox_set_trace_path)
		fprintf(stderr,"Warning: Tracing not supported in this sandbox version (can't get set_trace_path - %p)\n", sblibhandle);
		else {
			rc = sandbox_set_trace_path(compiled_profile,tracePath); 

		}
#endif
		if (rc == 0) fprintf(stderr,"Tracing to %s\n", tracePath);
		else fprintf(stderr,"Tracing error - Unable to trace to %s\n", tracePath);

	} 


	fprintf(stderr,"Applying container\n");
	rc =  sandbox_apply_container (compiled_profile, flags);

	if (rc != 0) { perror("sandbox_apply_container"); }
	
	fflush(NULL);
	if (compiled_profile) sandbox_free_profile(compiled_profile);
	fprintf (stderr, "EXECING %s\n", argv[optind]);
	execvp (argv[optind], argv+optind);

	perror("execvp");


}