/* Run a Hurd program under the Mach 3 Unix single-server.
   Responds to either boot_getports or exec_startup RPCs
   on the new task's bootstrap port.  */

#include <stddef.h>
#include <string.h>
#include <mach.h>
#include <mach/notify.h>
#include <mach/task_special_ports.h>

#define task_by_pid(foo) syscall (-33, foo)
#define myfork() syscall (2)
#define execve(foo1, foo2, foo3) syscall (59, foo1, foo2, foo3)
#define write(foo1, foo2, foo3) syscall (4, foo1, foo2, foo3)
#define getpid() syscall (20)

void
boot_ports (mach_port_t bootstrap_port)
{
  struct imsg {
    mach_msg_header_t	hdr;
    mach_msg_type_t	port_desc_1;
    mach_port_t		port_1;
    mach_msg_type_t	port_desc_2;
    mach_port_t		port_2;
  } imsg;
  kern_return_t result;
  
  /*
   * Wait for the port-request message
   */
  while (mach_msg(&imsg.hdr, MACH_RCV_MSG,
		  0, sizeof imsg.hdr, bootstrap_port,
		  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
	 != MACH_MSG_SUCCESS)
    continue;
  
  /*
   * Send back the host and device ports
   */
  
  imsg.hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX |
    MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(imsg.hdr.msgh_bits), 0);
  /* msgh_size doesn't need to be initialized */
  /* leave msgh_remote_port untouched */
  imsg.hdr.msgh_local_port = MACH_PORT_NULL;
  /* leave msgh_kind untouched */
  imsg.hdr.msgh_id += 100;	/* this is a reply msg */
  
  imsg.port_desc_1.msgt_name = MACH_MSG_TYPE_COPY_SEND;
  imsg.port_desc_1.msgt_size = 32;
  imsg.port_desc_1.msgt_number = 1;
  imsg.port_desc_1.msgt_inline = TRUE;
  imsg.port_desc_1.msgt_longform = FALSE;
  imsg.port_desc_1.msgt_deallocate = FALSE;
  imsg.port_desc_1.msgt_unused = 0;
  
  imsg.port_1	= task_by_pid (-1);
  
  imsg.port_desc_2 = imsg.port_desc_1;
  
  imsg.port_2	= task_by_pid (-2);
  
  result = mach_msg(&imsg.hdr, MACH_SEND_MSG,
		    sizeof imsg, 0, MACH_PORT_NULL,
		    MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
}

int
main (int argc, char **argv, char **envp)
{
  mach_port_t boot, ignore;
  char **p;
  char *s;
  int parpid;
  int mypid;

  mach_port_allocate (mach_task_self (),
		      MACH_PORT_RIGHT_RECEIVE,
		      &boot);

  mach_port_insert_right (mach_task_self (),
			  MACH_PORT_RIGHT_SEND,
			  boot,
			  MACH_PORT_TYPE_RECEIVE);

  write (1, "test\n", 5);
  parpid = getpid ();

  mypid = myfork ();
  write (1, "after fork\n", 11);
  if (mypid == -1)
    {
      write (1, "error!\n", 7);
      /*       perror ("fork"); */
      exit (1);
    }
  else if (mypid != parpid)
    {
      write (1, "execing ", 8);
      write (1, argv[1], strlen (argv[1]));
      write (1, "\n", 1);
      task_set_bootstrap_port (mach_task_self (), boot);
      execve (argv[1], &argv[1], envp);
      write (1, "exec failed\n", 12);
      /*       perror (argv[1]);*/
      exit (1);
    }
  else
    {
      write (1, "parent?\n", 8);
      boot_ports (boot);
      exit (0);
    }
}
