static int send_port (mach_port_t remote_port, mach_port_t port) { kern_return_t err; struct { mach_msg_header_t header; mach_msg_body_t body; mach_msg_port_descriptor_t task_port; } msg; msg.header.msgh_remote_port = remote_port; msg.header.msgh_local_port = MACH_PORT_NULL; msg.header.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX; msg.header.msgh_size = sizeof msg; msg.body.msgh_descriptor_count = 1; msg.task_port.name = port; msg.task_port.disposition = MACH_MSG_TYPE_COPY_SEND; msg.task_port.type = MACH_MSG_PORT_DESCRIPTOR; err = mach_msg_send (&msg.header); CHECK_MACH_ERROR (err, "mach_msg_send failed:"); return 0; }
static int setup_recv_port (mach_port_t *recv_port) { kern_return_t err; mach_port_t port = MACH_PORT_NULL; err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &port); CHECK_MACH_ERROR (err, "mach_port_allocate failed:"); err = mach_port_insert_right (mach_task_self (), port, port, MACH_MSG_TYPE_MAKE_SEND); CHECK_MACH_ERROR (err, "mach_port_insert_right failed:"); *recv_port = port; return 0; }
int main(void) { ERR_FILE = fopen("/tmp/FortunateSonErrorFile.txt", "a"); fprintf(ERR_FILE, "Started with pid %d\n", getpid()); mach_port_t parent_recv_port = get_hex_fiend_receive_port(); // Get notified when the parent receive port dies mach_port_t my_task = mach_task_self(); mach_port_t notificationPort = MACH_PORT_NULL; CHECK_MACH_ERROR(mach_port_allocate(my_task, MACH_PORT_RIGHT_RECEIVE, ¬ificationPort)); mach_port_t old; CHECK_MACH_ERROR(mach_port_request_notification(my_task, parent_recv_port, MACH_NOTIFY_NO_SENDERS, 0/*sync*/, notificationPort, MACH_MSG_TYPE_MAKE_SEND_ONCE, &old)); /* Make a port set */ mach_port_t portSet = MACH_PORT_NULL; CHECK_MACH_ERROR(mach_port_allocate(my_task, MACH_PORT_RIGHT_PORT_SET, &portSet)); CHECK_MACH_ERROR(mach_port_insert_member(my_task, parent_recv_port, portSet)); CHECK_MACH_ERROR(mach_port_insert_member(my_task, notificationPort, portSet)); run_server(portSet, notificationPort); /* Once run_server returns, we're done, so exit */ return 0; }
static int recv_port (mach_port_t recv_port, mach_port_t *port) { kern_return_t err; struct { mach_msg_header_t header; mach_msg_body_t body; mach_msg_port_descriptor_t task_port; mach_msg_trailer_t trailer; } msg; err = mach_msg (&msg.header, MACH_RCV_MSG, 0, sizeof msg, recv_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); CHECK_MACH_ERROR (err, "mach_msg failed:"); *port = msg.task_port.name; return 0; }
pid_t sampling_fork () { kern_return_t err; mach_port_t parent_recv_port = MACH_PORT_NULL; mach_port_t child_recv_port = MACH_PORT_NULL; if (setup_recv_port (&parent_recv_port) != 0) return -1; err = task_set_bootstrap_port (mach_task_self (), parent_recv_port); CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); pid_t pid; switch (pid = fork ()) { case -1: err = mach_port_deallocate (mach_task_self(), parent_recv_port); CHECK_MACH_ERROR (err, "mach_port_deallocate failed:"); return pid; case 0: /* child */ err = task_get_bootstrap_port (mach_task_self (), &parent_recv_port); CHECK_MACH_ERROR (err, "task_get_bootstrap_port failed:"); if (setup_recv_port (&child_recv_port) != 0) return -1; if (send_port (parent_recv_port, mach_task_self ()) != 0) return -1; if (send_port (parent_recv_port, child_recv_port) != 0) return -1; if (recv_port (child_recv_port, &bootstrap_port) != 0) return -1; err = task_set_bootstrap_port (mach_task_self (), bootstrap_port); CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); break; default: /* parent */ err = task_set_bootstrap_port (mach_task_self (), bootstrap_port); CHECK_MACH_ERROR (err, "task_set_bootstrap_port failed:"); if (recv_port (parent_recv_port, &child_task) != 0) return -1; if (recv_port (parent_recv_port, &child_recv_port) != 0) return -1; if (send_port (child_recv_port, bootstrap_port) != 0) return -1; err = mach_port_deallocate (mach_task_self(), parent_recv_port); CHECK_MACH_ERROR (err, "mach_port_deallocate failed:"); break; } return pid; }