diff options
Diffstat (limited to 'utils/msgport.c')
-rw-r--r-- | utils/msgport.c | 284 |
1 files changed, 183 insertions, 101 deletions
diff --git a/utils/msgport.c b/utils/msgport.c index 10449e04..eed174b7 100644 --- a/utils/msgport.c +++ b/utils/msgport.c @@ -32,13 +32,13 @@ #include <version.h> #include "pids.h" +/* From libc (not in hurd.h) */ char * _hurd_canonicalize_directory_name_internal (file_t thisdir, char *buf, size_t size); const char *argp_program_version = STANDARD_HURD_VERSION (msgport); - static const struct argp_option options[] = { @@ -53,40 +53,73 @@ static const char args_doc[] = +/* All command functions match this prototype. */ typedef error_t (*cmd_func_t) (pid_t pid, mach_port_t msgport, int argc, char *argv[]); +/* One of these is created for each command given in the command line. */ typedef struct cmd { + /* Function to execute for this command */ cmd_func_t f; + + /* Array of arguments that will be passed to function F */ char **args; size_t num_args; } cmd_t; -struct cmds_argp_params + +/* Execute command CMD on process PID */ +error_t +do_cmd (pid_t pid, cmd_t cmd) { - cmd_t **cmds; - size_t *num_cmds; -}; + error_t err; + mach_port_t msgport; + process_t proc = getproc (); + /* Get a msgport for PID, to which we can send requests. */ + err = proc_getmsgport (proc, pid, &msgport); + if (err) + error (1, err, "%d: Cannot get process msgport", pid); - + err = (*cmd.f) (pid, msgport, cmd.num_args, cmd.args); + if (err) + error (2, err, "%d: Cannot execute command", pid); -static error_t + mach_port_deallocate (mach_task_self (), msgport); + return 0; +} + + +/* All these functions, whose name start with cmd_, execute some + commands on the process PID, by sending messages (see msg.defs) to + its message port, which is MSGPORT. ARGC and ARGV are as in main. + They return zero iff successful. */ + +/* Print the name and value of the environment variable ARGV[0]. + Without arguments (ARGC==0), print the names and values of all + environment variables. */ +error_t cmd_getenv (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; + + /* Memory will be vm_allocated by msg_get_* if the result does not + fit in buf. */ char buf[1024], *data = buf; mach_msg_type_number_t len = sizeof (buf); + if (argc) { - if ((err = msg_get_env_variable (msgport, argv[0], &data, &len))) + err = msg_get_env_variable (msgport, argv[0], &data, &len); + if (err) return err; printf ("%d: %s=%s\n", pid, argv[0], data); } - else + else /* get the whole environment */ { char *p; - if ((err = msg_get_environment (msgport, &data, &len))) + err = msg_get_environment (msgport, &data, &len); + if (err) return err; for (p=data; p < data + len; p = strchr (p, '\0') + 1) printf ("%d: %s\n", pid, p); @@ -96,35 +129,42 @@ cmd_getenv (pid_t pid, mach_port_t msgport, int argc, char *argv[]) return err; } -static error_t +/* Set environment variable ARGV[0] to the value ARGV[1]. */ +error_t cmd_setenv (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; task_t task; process_t proc = getproc (); - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) return err; err = msg_set_env_variable (msgport, task, argv[0], argv[1], 1); mach_port_deallocate (mach_task_self (), task); return err; } -static error_t +/* Clear environment. */ +error_t cmd_clearenv (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; task_t task; process_t proc = getproc (); - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) return err; err = msg_set_environment (msgport, task, 0, 0); mach_port_deallocate (mach_task_self (), task); return err; } -static int +/* Convert string STR in flags for file access modes. STR should be a + combination of `r', `w' and `x' (for read, write and execute modes + respectively). Other chars are ignored. */ +int str2flags (char *str) { int flags = 0; @@ -143,21 +183,28 @@ str2flags (char *str) return flags; } -static error_t +/* Set port associated to file descriptor FD of process PID, whose + message port is MSGPORT, to FILE. Used by + cmd_{setfd,stdin,stdout,stderr}. */ +error_t do_setfd (pid_t pid, mach_port_t msgport, size_t fd, file_t file) { error_t err; task_t task; process_t proc = getproc (); - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) return err; err = msg_set_fd (msgport, task, fd, file, MACH_MSG_TYPE_MOVE_SEND); mach_port_deallocate (mach_task_self (), task); return err; } -static error_t +/* Set port associated to file descriptor ARGV[0] to the file ARGV[1]. + File access mode is given by ARGV[2] (see str2flags). If no access + mode is given, the default is O_RDONLY. */ +error_t cmd_setfd (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -166,15 +213,18 @@ cmd_setfd (pid_t pid, mach_port_t msgport, int argc, char *argv[]) if (argc > 2) flags = str2flags(argv[2]); - if ((file = file_name_lookup (argv[1], flags, 0666)) == - MACH_PORT_NULL) + file = file_name_lookup (argv[1], flags, 0666); + if (file == MACH_PORT_NULL) return errno; - if ((err = do_setfd (pid, msgport, atoi (argv[0]), file))) + err = do_setfd (pid, msgport, atoi (argv[0]), file); + if (err) mach_port_deallocate (mach_task_self (), file); return err; } -static error_t +/* Set standard input to ARGV[0]. Optionally, ARGV[1] may specify the + file access mode (see str2flags). The default is O_RDONLY */ +error_t cmd_stdin (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -183,15 +233,18 @@ cmd_stdin (pid_t pid, mach_port_t msgport, int argc, char *argv[]) if (argc > 1) flags = str2flags(argv[1]); - if ((file = file_name_lookup (argv[0], flags, 0666)) == - MACH_PORT_NULL) + file = file_name_lookup (argv[0], flags, 0666); + if (file == MACH_PORT_NULL) return errno; - if ((err = do_setfd (pid, msgport, 0, file))) + err = do_setfd (pid, msgport, 0, file); + if (err) mach_port_deallocate (mach_task_self (), file); return err; } -static error_t +/* Set standard output to ARGV[0]. Optionally, ARGV[1] may specify the + file access mode (see str2flags). The default is O_WRONLY */ +error_t cmd_stdout (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -200,15 +253,18 @@ cmd_stdout (pid_t pid, mach_port_t msgport, int argc, char *argv[]) if (argc > 1) flags = str2flags(argv[1]); - if ((file = file_name_lookup (argv[0], flags, 0666)) == - MACH_PORT_NULL) + file = file_name_lookup (argv[0], flags, 0666); + if (file == MACH_PORT_NULL) return errno; - if ((err = do_setfd (pid, msgport, 1, file))) + err = do_setfd (pid, msgport, 1, file); + if (err) mach_port_deallocate (mach_task_self (), file); return err; } -static error_t +/* Set standard error to ARGV[0]. Optionally, ARGV[1] may specify the + file access mode (see str2flags). The default is O_RDONLY */ +error_t cmd_stderr (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -217,15 +273,17 @@ cmd_stderr (pid_t pid, mach_port_t msgport, int argc, char *argv[]) if (argc > 1) flags = str2flags(argv[1]); - if ((file = file_name_lookup (argv[0], flags, 0666)) == - MACH_PORT_NULL) + file = file_name_lookup (argv[0], flags, 0666); + if (file == MACH_PORT_NULL) return errno; - if ((err = do_setfd (pid, msgport, 2, file))) + err = do_setfd (pid, msgport, 2, file); + if (err) mach_port_deallocate (mach_task_self (), file); return err; } -static error_t +/* Change current working directory to ARGV[0]. */ +error_t cmd_chcwdir (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -233,21 +291,25 @@ cmd_chcwdir (pid_t pid, mach_port_t msgport, int argc, char *argv[]) task_t task; process_t proc = getproc (); - if ((dir = file_name_lookup (argv[0], 0, 0)) == MACH_PORT_NULL) + dir = file_name_lookup (argv[0], 0, 0); + if (dir == MACH_PORT_NULL) return errno; - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) { mach_port_deallocate (mach_task_self (), dir); return err; } - if ((err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir, - MACH_MSG_TYPE_MOVE_SEND))) + err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir, + MACH_MSG_TYPE_MOVE_SEND); + if (err) mach_port_deallocate (mach_task_self (), dir); mach_port_deallocate (mach_task_self (), task); return err; } -static error_t +/* Change current working directory to current root directory. */ +error_t cmd_cdroot (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -255,21 +317,25 @@ cmd_cdroot (pid_t pid, mach_port_t msgport, int argc, char *argv[]) task_t task; process_t proc = getproc (); - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) return err; - if ((err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir))) + err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir); + if (err) { mach_port_deallocate (mach_task_self (), task); return err; } - if ((err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir, - MACH_MSG_TYPE_MOVE_SEND))) + err = msg_set_init_port (msgport, task, INIT_PORT_CWDIR, dir, + MACH_MSG_TYPE_MOVE_SEND); + if (err) mach_port_deallocate (mach_task_self (), dir); mach_port_deallocate (mach_task_self (), task); return err; } -static error_t +/* Change current root directory to ARGV[0]. */ +error_t cmd_chcrdir (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -277,21 +343,25 @@ cmd_chcrdir (pid_t pid, mach_port_t msgport, int argc, char *argv[]) task_t task; process_t proc = getproc (); - if ((dir = file_name_lookup (argv[0], 0, 0)) == MACH_PORT_NULL) + dir = file_name_lookup (argv[0], 0, 0); + if (dir == MACH_PORT_NULL) return errno; - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) { mach_port_deallocate (mach_task_self (), dir); return err; } - if ((err = msg_set_init_port (msgport, task, INIT_PORT_CRDIR, dir, - MACH_MSG_TYPE_MOVE_SEND))) + err = msg_set_init_port (msgport, task, INIT_PORT_CRDIR, dir, + MACH_MSG_TYPE_MOVE_SEND); + if (err) mach_port_deallocate (mach_task_self (), dir); mach_port_deallocate (mach_task_self (), task); return err; } -static error_t +/* Print current working directory. */ +error_t cmd_pwd (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -299,9 +369,11 @@ cmd_pwd (pid_t pid, mach_port_t msgport, int argc, char *argv[]) task_t task; process_t proc = getproc (); - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) return err; - if ((err = msg_get_init_port (msgport, task, INIT_PORT_CWDIR, &dir))) + err = msg_get_init_port (msgport, task, INIT_PORT_CWDIR, &dir); + if (err) { mach_port_deallocate (mach_task_self (), task); return err; @@ -313,7 +385,8 @@ cmd_pwd (pid_t pid, mach_port_t msgport, int argc, char *argv[]) return 0; } -static error_t +/* Print current root directory */ +error_t cmd_getroot (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -321,9 +394,11 @@ cmd_getroot (pid_t pid, mach_port_t msgport, int argc, char *argv[]) task_t task; process_t proc = getproc (); - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) return err; - if ((err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir))) + err = msg_get_init_port (msgport, task, INIT_PORT_CRDIR, &dir); + if (err) { mach_port_deallocate (mach_task_self (), task); return err; @@ -335,7 +410,9 @@ cmd_getroot (pid_t pid, mach_port_t msgport, int argc, char *argv[]) return 0; } -static error_t +/* Change umask to ARGV[0] (octal value). Without arguments, print + the value of current umask. */ +error_t cmd_umask (pid_t pid, mach_port_t msgport, int argc, char *argv[]) { error_t err; @@ -343,15 +420,20 @@ cmd_umask (pid_t pid, mach_port_t msgport, int argc, char *argv[]) task_t task; process_t proc = getproc (); - if ((err = proc_pid2task (proc, pid, &task))) + err = proc_pid2task (proc, pid, &task); + if (err) return err; if (argc) { umask = strtol(argv[0], 0, 8); err = msg_set_init_int (msgport, task, INIT_UMASK, umask); } - else if (!(err = msg_get_init_int (msgport, task, INIT_UMASK, &umask))) - printf ("%d: %03o\n", pid, umask); + else + { + err = msg_get_init_int (msgport, task, INIT_UMASK, &umask); + if (!err) + printf ("%d: %03o\n", pid, umask); + } mach_port_deallocate (mach_task_self (), task); return err; } @@ -373,6 +455,14 @@ cmd_umask (pid_t pid, mach_port_t msgport, int argc, char *argv[]) #define CMD_PWD 1011 #define CMD_GETROOT 1012 +/* Params to be passed as the input when parsing CMDS_ARGP. */ +struct cmds_argp_params +{ + /* Array to be extended with parsed cmds. */ + cmd_t **cmds; + size_t *num_cmds; +}; + static const struct argp_option cmd_options[] = { {"getenv", CMD_GETENV, "VAR", OA, "Get environment variable"}, @@ -394,8 +484,15 @@ static const struct argp_option cmd_options[] = {0, 0} }; +/* Add a new command to the array of commands already parsed + reallocating it in malloced memory. FUNC is the command function. + MINARGS and MAXARGS are the minimum and maximum number of arguments + the parser will accept for this command. Further checking of the + arguments should be done in FUNC. ARG is the next argument in the + command line (probably the first argument for this command). STATE + is the argp parser state as used in parse_cmd_opt. */ static error_t -cmd_add (cmd_func_t func, size_t minargs, size_t maxargs, +add_cmd (cmd_func_t func, size_t minargs, size_t maxargs, char *arg, struct argp_state *state) { cmd_t *cmd; @@ -416,9 +513,9 @@ cmd_add (cmd_func_t func, size_t minargs, size_t maxargs, cmd->args = malloc (maxargs * sizeof (char *)); if (arg) cmd->args[i++] = arg; - while (i < maxargs && - state->argv[state->next] && - state->argv[state->next][0] != '-') + while (i < maxargs + && state->argv[state->next] + && state->argv[state->next][0] != '-') cmd->args[i++] = state->argv[state->next++]; } if (i < minargs || i > maxargs) @@ -427,8 +524,9 @@ cmd_add (cmd_func_t func, size_t minargs, size_t maxargs, return 0; } +/* Parse one option/arg for the argp parser cmds_argp (see argp.h). */ static error_t -cmd_parse_opt (int key, char *arg, struct argp_state *state) +parse_cmd_opt (int key, char *arg, struct argp_state *state) { /* A buffer used for rewriting command line arguments without dashes for the parser to understand them. It gets realloced for each @@ -439,8 +537,9 @@ cmd_parse_opt (int key, char *arg, struct argp_state *state) { case ARGP_KEY_ARG: /* Non-option argument. */ if (!isdigit (*arg) && !state->quoted) - /* Prepend 2 dashes and feed back to getopt. */ { + /* Make state->next point to the just parsed argument to + re-parse it with 2 dashes prepended. */ size_t len = strlen (arg) + 1; arg_hack_buf = realloc (arg_hack_buf, 2 + len); state->argv[--state->next] = arg_hack_buf; @@ -452,43 +551,43 @@ cmd_parse_opt (int key, char *arg, struct argp_state *state) else return ARGP_ERR_UNKNOWN; case CMD_CHCWDIR: - cmd_add (&cmd_chcwdir, 0, 1, arg, state); + add_cmd (&cmd_chcwdir, 0, 1, arg, state); break; case CMD_CHCRDIR: - cmd_add (&cmd_chcrdir, 1, 1, arg, state); + add_cmd (&cmd_chcrdir, 1, 1, arg, state); break; case CMD_CDROOT: - cmd_add (&cmd_cdroot, 0, 0, arg, state); + add_cmd (&cmd_cdroot, 0, 0, arg, state); break; case CMD_PWD: - cmd_add (&cmd_pwd, 0, 0, arg, state); + add_cmd (&cmd_pwd, 0, 0, arg, state); break; case CMD_GETROOT: - cmd_add (&cmd_getroot, 0, 0, arg, state); + add_cmd (&cmd_getroot, 0, 0, arg, state); break; case CMD_UMASK: - cmd_add (&cmd_umask, 0, 1, arg, state); + add_cmd (&cmd_umask, 0, 1, arg, state); break; case CMD_GETENV: - cmd_add (&cmd_getenv, 0, 1, arg, state); + add_cmd (&cmd_getenv, 0, 1, arg, state); break; case CMD_SETENV: - cmd_add (&cmd_setenv, 2, 2, arg, state); + add_cmd (&cmd_setenv, 2, 2, arg, state); break; case CMD_CLRENV: - cmd_add (&cmd_clearenv, 0, 0, arg, state); + add_cmd (&cmd_clearenv, 0, 0, arg, state); break; case CMD_SETFD: - cmd_add (&cmd_setfd, 2, 3, arg, state); + add_cmd (&cmd_setfd, 2, 3, arg, state); break; case CMD_STDIN: - cmd_add (&cmd_stdin, 1, 2, arg, state); + add_cmd (&cmd_stdin, 1, 2, arg, state); break; case CMD_STDOUT: - cmd_add (&cmd_stdout, 1, 2, arg, state); + add_cmd (&cmd_stdout, 1, 2, arg, state); break; case CMD_STDERR: - cmd_add (&cmd_stderr, 1, 2, arg, state); + add_cmd (&cmd_stderr, 1, 2, arg, state); break; default: return ARGP_ERR_UNKNOWN; @@ -496,6 +595,9 @@ cmd_parse_opt (int key, char *arg, struct argp_state *state) return 0; } +/* Filtering of help output strings for cmds_argp parser. Return a + malloced replacement for TEXT as the arguments doc string. See + argp.h for details. */ static char * help_filter (int key, const char *text, void *input) { @@ -505,31 +607,11 @@ help_filter (int key, const char *text, void *input) return (char *)text; } -/* A parser for selecting a command. */ -struct argp cmds_argp = { cmd_options, cmd_parse_opt, 0, 0, 0, help_filter }; - -static error_t -do_cmd (pid_t pid, cmd_t cmd) -{ - error_t err; - mach_port_t msgport; - process_t proc = getproc (); - - /* Get a msgport for PID, to which we can send requests. */ - err = proc_getmsgport (proc, pid, &msgport); - if (err) - error (1, err, "%d: Cannot get process msgport", pid); - - err = (*cmd.f) (pid, msgport, cmd.num_args, cmd.args); - if (err) - error (2, err, "%d: Cannot execute command", pid); - - mach_port_deallocate (mach_task_self (), msgport); - return 0; -} - +/* An argp parser for selecting a command (see argp.h). */ +struct argp cmds_argp = { cmd_options, parse_cmd_opt, 0, 0, 0, help_filter }; + int main(int argc, char *argv[]) { @@ -586,7 +668,7 @@ main(int argc, char *argv[]) for (j = 0; j < num_cmds; ++j) { cmd = cmds[j]; - if ((err = do_cmd(pid, cmd))) + if ((err = do_cmd (pid, cmd))) error (2, err, "%d: Cannot execute command", pid); } } |