#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <bootstrap.h> // for bootstrap *
#include <mach/mach_port.h> // for mach_port*, ipc_space
#include <mach/mach_init.h> // for mach_task_self

#include <stdlib.h>
int main(int argc, char **argv, char **envp, char **apple) {


	extern mach_port_t	bootstrap_port; // defined in libsystem_kernel.dylib

	printf("My BS Port (SEND RIGHT) - is 0x%x\n", bootstrap_port); 


char *mach_error_string(int); // in some header, whatever

#ifdef LOOKUP
	mach_port_t 	server_p = MACH_PORT_NULL;
	kern_return_t  kr = bootstrap_look_up (bootstrap_port, // from bootstrap.h
					argv[1],
					&server_p);


	if (KERN_SUCCESS == kr) { printf("SERVER P is 0x%x\n", server_p);}

	else {
			fprintf(stderr,"bootstrap_look_up: %s\n" , mach_error_string(kr));

		}


#endif // LOOKUP

#ifdef ENUM


	ipc_space_t target = mach_task_self(); // given representing MOI.

	kern_return_t kr = task_for_pid(mach_task_self(),
			   atoi(argv[1]),
			&target);

	if (kr != KERN_SUCCESS) {

		fprintf(stderr," FOOL! You cannot unleash the dark magicks! Away with thee! (%s)\n",
				mach_error_string(kr));
		exit(1);

	}

	mach_port_t 	myEphPort = MACH_PORT_NULL; // unallocated constant 

#define MAX_PORTS_FOR_FUN	1
	for (int i = 0; i < MAX_PORTS_FOR_FUN; i++) {
	kr = mach_port_allocate 
		(target, // ipc_space_t task,
		 MACH_PORT_RIGHT_RECEIVE , // mach_port_right_t right,
		&myEphPort); // mach_port_name_t *name);

	mach_port_insert_right (target,
			myEphPort,
			myEphPort,
			MACH_MSG_TYPE_MAKE_SEND);
	
	(void) kr; // @@TODO: check me. Should be KERN_SUCCESS
	printf("My Eph port is 0x%x\n", myEphPort);

	}

	// There are more port (rights) in my space than I necessarily know.
	// and - there is some API to ENUMERATE.

        ipc_info_space_t space_info;
        ipc_info_name_array_t table_info;
        mach_msg_type_number_t table_infoCnt;
        ipc_info_tree_name_array_t tree_info;
        mach_msg_type_number_t tree_infoCnt;

	kern_return_t kr1 = mach_port_space_info
		(target, // ipc_space_read_t space,
		&space_info, // ipc_info_space_t *space_info,
		&table_info , // ipc_info_name_array_t *table_info,
		&table_infoCnt, // mach_msg_type_number_t *table_infoCnt,
		&tree_info, // ipc_info_tree_name_array_t *tree_info,   // IRRELEVANT (unused)
		&tree_infoCnt); // mach_msg_type_number_t *tree_infoCnt // IRRELEVANT (unused)
	
	if (KERN_SUCCESS != kr1) {
		fprintf(stderr," mach_port_space_info: %s\n", mach_error_string(kr1));
		exit(1);

	}

	printf("Table count: %d\n", table_infoCnt);
	int p  = 0;
	for (p = 0;  p < table_infoCnt; p++) {

#if 0
typedef struct ipc_info_name {
        mach_port_name_t iin_name;              /* port name, including gen number */
/*boolean_t*/ integer_t iin_collision;   /* collision at this entry? */
        mach_port_type_t iin_type;      /* straight port type */
        mach_port_urefs_t iin_urefs;    /* user-references */
        natural_t iin_object;           /* object pointer/identifier */
        natural_t iin_next;             /* marequest/next in free list */
        natural_t iin_hash;             /* hash index */
} ipc_info_name_t;
#endif 
		printf("%d: name 0x%x type 0x%x obj 0x%x\n" ,
			p,
			table_info[p].iin_name,
			table_info[p].iin_type,
			table_info[p].iin_object);


	}// end p
#endif // ENUM 
} // end main