/* Print information about a task's ports Copyright (C) 1996,97,98,99, 2000,13 Free Software Foundation, Inc. Written by Miles Bader This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const char *argp_program_version = STANDARD_HURD_VERSION (portinfo); static const struct argp_option options[] = { {0,0,0,0,0, 1}, {"verbose", 'v', 0, 0, "Give more detailed information"}, {"members", 'm', 0, 0, "Show members of port-sets"}, {"hex-names", 'x', 0, 0, "Show port names in hexadecimal"}, #if 0 /* XXX implement this */ {"query-process", 'q', 0, 0, "Query the process itself for the identity of" " the ports in question -- requires the process be in a sane state"}, #endif {"hold", '*', 0, OPTION_HIDDEN}, {0,0,0,0, "Selecting which names to show:", 2}, {"receive", 'r', 0, 0, "Show ports with receive rights"}, {"send", 's', 0, 0, "Show ports with send rights"}, {"send-once", 'o', 0, 0, "Show ports with send once rights"}, {"dead-names",'d', 0, 0, "Show dead names"}, {"port-sets", 'p', 0, 0, "Show port sets"}, {0,0,0,0, "Translating port names between tasks:", 3}, {"translate", 't', "PID", 0, "Translate port names to process PID"}, #if 0 {"show-targets", 'h', 0, 0, "Print a header describing the target process" }, #endif {"no-translation-errors", 'E', 0, 0, "Don't display an error if a specified port can't be translated" }, {"search", 'a', 0, 0, "Search all processes for the given ports"}, #if 0 {"target-receive", 'R', 0, 0, "Only show ports that translate into receive rights"}, {"target-send", 'S', 0, 0, "Only show ports that translate into send rights"}, {"target-send-once",'O', 0, 0, "Only show ports that translate into send-once rights"}, "Only show ports that translate into send once rights"}, #endif {0} }; static const char *args_doc = "PID [NAME...]"; static const char *doc = "Show information about mach ports NAME... (default all ports) in process PID." "\vIf no port NAMEs are given, all ports in process PID are reported (if" " translation is used, then only those common to both processes). NAMEs" " may be specified in hexadecimal or octal by using a 0x or 0 prefix."; /* Return the task corresponding to the user argument ARG, exiting with an appriate error message if we can't. */ static task_t parse_task (char *arg) { error_t err; task_t task; char *arg_end; pid_t pid = strtoul (arg, &arg_end, 10); static process_t proc = MACH_PORT_NULL; if (*arg == '\0' || *arg_end != '\0') error (10, 0, "%s: Invalid process id", arg); if (proc == MACH_PORT_NULL) proc = getproc (); err = proc_pid2task (proc, pid, &task); if (err) error (11, err, "%s", arg); else if (task == MACH_PORT_NULL) error (11, 0, "%s: Process %d is dead and has no task", arg, (int) pid); return task; } /* Functions searching for local ports in all processes. */ /* Locates the port NAME from TASK in any other process and prints the mappings. */ error_t search_for_port (task_t task, mach_port_t name, unsigned show) { error_t err; /* These resources are freed in the function epilogue. */ struct ps_context *context = NULL; struct proc_stat_list *procset = NULL; /* Print infos about this port. */ err = print_port_info (name, 0, task, show, stdout); if (err) goto out; static process_t proc = MACH_PORT_NULL; if (proc == MACH_PORT_NULL) proc = getproc (); pid_t pid; err = proc_task2pid (proc, task, &pid); if (err) goto out; /* Get a list of all processes. */ err = ps_context_create (getproc (), &context); if (err) goto out; err = proc_stat_list_create (context, &procset); if (err) goto out; err = proc_stat_list_add_all (procset, 0, 0); if (err) goto out; for (unsigned i = 0; i < procset->num_procs; i++) { /* Ignore the target process. */ if (procset->proc_stats[i]->pid == pid) continue; task_t xlate_task = MACH_PORT_NULL; err = proc_pid2task (proc, procset->proc_stats[i]->pid, &xlate_task); if (err || xlate_task == MACH_PORT_NULL) continue; struct port_name_xlator *xlator = NULL; err = port_name_xlator_create (task, xlate_task, &xlator); if (err) goto loop_cleanup; mach_port_t translated_port; mach_msg_type_name_t translated_type; err = port_name_xlator_xlate (xlator, name, 0, &translated_port, &translated_type); if (err) goto loop_cleanup; /* The port translation was successful, print more infos. */ printf ("% 5i -> % 5i: ", pid, procset->proc_stats[i]->pid); err = print_xlated_port_info (name, 0, xlator, show, stdout); if (err) goto loop_cleanup; loop_cleanup: if (xlate_task) mach_port_deallocate (mach_task_self (), xlate_task); if (xlator) port_name_xlator_free (xlator); } err = 0; out: if (procset != NULL) proc_stat_list_free (procset); if (context != NULL) ps_context_free (context); return err; } /* Locates all ports from TASK in any other process and prints the mappings. */ error_t search_for_ports (task_t task, mach_port_type_t only, unsigned show) { error_t err; mach_port_t *names = NULL; mach_port_type_t *types = NULL; mach_msg_type_number_t names_len = 0; mach_msg_type_number_t types_len = 0; err = mach_port_names (task, &names, &names_len, &types, &types_len); if (err) return err; for (mach_msg_type_number_t i = 0; i < names_len; i++) if (types[i] & only) search_for_port (task, names[i], show); munmap ((caddr_t) names, names_len * sizeof *names); munmap ((caddr_t) types, types_len * sizeof *types); return 0; } static volatile int hold = 0; int main (int argc, char **argv) { error_t err; task_t task; int search = 0; unsigned show = 0; /* what info we print */ mach_port_type_t only = 0, target_only = 0; /* Which names to show */ task_t xlate_task = MACH_PORT_NULL; int no_translation_errors = 0; /* inhibit complaints about bad names */ struct port_name_xlator *xlator = 0; /* Parse our options... */ error_t parse_opt (int key, char *arg, struct argp_state *state) { switch (key) { case 'v': show |= PORTINFO_DETAILS; break; case 'm': show |= PORTINFO_MEMBERS; break; case 'x': show |= PORTINFO_HEX_NAMES; break; case 'r': only |= MACH_PORT_TYPE_RECEIVE; break; case 's': only |= MACH_PORT_TYPE_SEND; break; case 'o': only |= MACH_PORT_TYPE_SEND_ONCE; break; case 'd': only |= MACH_PORT_TYPE_DEAD_NAME; break; case 'p': only |= MACH_PORT_TYPE_PORT_SET; break; case 'R': target_only |= MACH_PORT_TYPE_RECEIVE; break; case 'S': target_only |= MACH_PORT_TYPE_SEND; break; case 'O': target_only |= MACH_PORT_TYPE_SEND_ONCE; break; case 't': xlate_task = parse_task (arg); break; case 'a': search = 1; break; case 'E': no_translation_errors = 1; break; case '*': hold = 1; while (hold) sleep (1); break; case ARGP_KEY_NO_ARGS: argp_usage (state); return EINVAL; case ARGP_KEY_ARG: if (state->arg_num == 0) /* The task */ { task = parse_task (arg); if (only == 0) only = ~0; if (target_only == 0) target_only = ~0; if (xlate_task != MACH_PORT_NULL) { if (search) argp_error (state, "Both --search and --translate specified"); err = port_name_xlator_create (task, xlate_task, &xlator); if (err) error (13, err, "Cannot setup task translation"); } if (state->next == state->argc) /* No port names specified, print all of them. */ { if (xlator) err = print_xlated_task_ports_info (xlator, only, show, stdout); else if (search) err = search_for_ports (task, only, show); else err = print_task_ports_info (task, only, show, stdout); if (err) error (12, err, "%s", arg); } break; } /* A port name */ { char *end; mach_port_t name = strtoul (arg, &end, 0); if (name == 0) error (0, 0, "%s: Invalid port name", arg); else { if (xlator) { err = print_xlated_port_info (name, 0, xlator, show, stdout); if (err && no_translation_errors) break; } else if (search) err = search_for_port (task, name, show); else err = print_port_info (name, 0, task, show, stdout); if (err) error (0, err, "%s", arg); } } break; default: return ARGP_ERR_UNKNOWN; } return 0; } const struct argp argp = { options, parse_opt, args_doc, doc }; /* Parse our arguments. */ argp_parse (&argp, argc, argv, 0, 0, 0); exit (0); }