diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-01-08 23:00:37 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-01-08 23:00:37 +0100 |
commit | 104f3121f8005b426d4df77b2420cfe5837033d1 (patch) | |
tree | 34bb93d3796e7c45dc1c67a5d40fb3bd1604ad9f | |
parent | 9d3ba19ddc56ad929f673af23eb87ab07ae30631 (diff) | |
download | hurd-104f3121f8005b426d4df77b2420cfe5837033d1.tar.gz hurd-104f3121f8005b426d4df77b2420cfe5837033d1.tar.bz2 hurd-104f3121f8005b426d4df77b2420cfe5837033d1.zip |
Implement /proc/<pid>/exe
by adding proc_set/get_exe to the proc server, making
exec call proc_set_exe, and libps call proc_get_exe. procfs can then just
retrieve the information to make the "exe" symlink.
* hurd/process.defs (proc_set_exe, proc_get_exe): New RPCs.
* hurd/process_request.defs: Likewise.
* hurd/process_reply.defs: Add skips for proc_set_exe and proc_get_exe RPCs.
* proc/proc.h (struct proc): Add `exe' field.
* proc/info.c (S_proc_set_exe, S_proc_get_exe): New functions.
* proc/mgt.c (process_has_exited): Free p->exe.
(S_proc_child): Duplicate parent `exe' into child's `exe'.
* exec/exec.c (do_exec): Call proc_set_exe when a filename is available.
* libps/ps.h (struct proc_stat): Add `exe_vm_alloced', `exe', and `exe_len'
field.
(PSTAT_EXE): New macro.
(PSTAT_USER_BASE): Change value to make room.
(proc_stat_exe, proc_stat_exe_len): New macros.
* libps/procstat.c (proc_stat_set_flags): Handle PSTAT_EXE case by calling
proc_get_exe.
* libps/spec.c (ps_get_exe): New function.
(ps_exe_getter): New structure.
(ps_fmt_spec): Add "Exe" specification.
* procfs/process.c (process_file_symlink_make_node, process_file_gc_exe): New
functions.
(procfs_dir_entry): Add "exe" entry.
* startup/startup.c (launch_core_servers): Set exe paths for startup, auth,
proc, and fs servers.
(frob_kernel_process): Set exe path for kernel task.
(S_startup_essential_task): Set exe path for exec server.
-rw-r--r-- | exec/exec.c | 3 | ||||
-rw-r--r-- | hurd/process.defs | 12 | ||||
-rw-r--r-- | libps/procstat.c | 17 | ||||
-rw-r--r-- | libps/ps.h | 11 | ||||
-rw-r--r-- | libps/spec.c | 10 | ||||
-rw-r--r-- | proc/info.c | 41 | ||||
-rw-r--r-- | proc/mgt.c | 4 | ||||
-rw-r--r-- | proc/proc.h | 1 | ||||
-rw-r--r-- | procfs/process.c | 32 | ||||
-rw-r--r-- | startup/startup.c | 7 |
10 files changed, 135 insertions, 3 deletions
diff --git a/exec/exec.c b/exec/exec.c index 94f0a733..e9590911 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -1314,6 +1314,9 @@ do_exec (file_t file, if (e.error) goto out; + if (abspath) + proc_set_exe (boot->portarray[INIT_PORT_PROC], abspath); + set_name (newtask, argv, pid); e.error = proc_set_entry (boot->portarray[INIT_PORT_PROC], diff --git a/hurd/process.defs b/hurd/process.defs index 725326a4..d515a46d 100644 --- a/hurd/process.defs +++ b/hurd/process.defs @@ -414,8 +414,16 @@ routine proc_make_task_namespace ( process: process_t; notify: mach_port_send_t); -skip; /* proc_set_exe */ -skip; /* proc_get_exe */ +/* Set the process binary executable path. */ +routine proc_set_exe ( + process: process_t; + path: string_t); + +/* Get the process binary executable path. */ +routine proc_get_exe ( + process: process_t; + which: pid_t; + out path: string_t); /* Set the locations of the executable entry. */ routine proc_set_entry ( diff --git a/libps/procstat.c b/libps/procstat.c index f6420eea..d0423410 100644 --- a/libps/procstat.c +++ b/libps/procstat.c @@ -956,6 +956,23 @@ proc_stat_set_flags (struct proc_stat *ps, ps_flags_t flags) } } + /* The process's path to binary executable */ + if (NEED (PSTAT_EXE, PSTAT_PID)) + { + ps->exe = malloc (sizeof(string_t)); + if (ps->exe) + { + if (proc_get_exe (server, ps->pid, ps->exe)) + free (ps->exe); + else + { + ps->exe_len = strlen(ps->exe); + have |= PSTAT_EXE; + ps->exe_vm_alloced = 0; + } + } + } + /* The ctty id port; note that this is just a magic cookie; we use it to fetch a port to the actual terminal -- it's not useful for much else. */ @@ -272,6 +272,7 @@ struct proc_stat unsigned thread_waits_vm_alloced : 1; unsigned args_vm_alloced : 1; unsigned env_vm_alloced : 1; + unsigned exe_vm_alloced : 1; /* Various libc ports: */ @@ -305,6 +306,11 @@ struct proc_stat size_t env_len; unsigned num_ports; + + /* The path to process's binary executable. */ + char *exe; + /* The length of EXE. */ + size_t exe_len; }; /* Proc_stat flag bits; each bit is set in the FLAGS field if that @@ -344,12 +350,13 @@ struct proc_stat #define PSTAT_HOOK 0x800000 /* Has a non-zero hook */ #define PSTAT_NUM_PORTS 0x4000000 /* Number of Mach ports in the task */ #define PSTAT_TIMES 0x8000000 /* Task/thread user and system times */ +#define PSTAT_EXE 0x10000000 /* Path to binary executable */ /* Flag bits that don't correspond precisely to any field. */ #define PSTAT_NO_MSGPORT 0x1000000 /* Don't use the msgport at all */ /* Bits from PSTAT_USER_BASE on up are available for user-use. */ -#define PSTAT_USER_BASE 0x10000000 +#define PSTAT_USER_BASE 0x20000000 #define PSTAT_USER_MASK ~(PSTAT_USER_BASE - 1) /* If the PSTAT_STATE flag is set, then the proc_stats state field holds a @@ -448,6 +455,8 @@ extern char *proc_stat_state_tags; #define proc_stat_tty(ps) ((ps)->tty) #define proc_stat_task_events_info(ps) ((ps)->task_events_info) #define proc_stat_num_ports(ps) ((ps)->num_ports) +#define proc_stat_exe(ps) ((ps)->exe) +#define proc_stat_exe_len(ps) ((ps)->exe_len) #define proc_stat_has(ps, needs) (((ps)->flags & needs) == needs) /* True if PS refers to a thread and not a process. */ diff --git a/libps/spec.c b/libps/spec.c index 5e540f87..4760c431 100644 --- a/libps/spec.c +++ b/libps/spec.c @@ -358,6 +358,14 @@ ps_get_num_ports (struct proc_stat *ps) const struct ps_getter ps_num_ports_getter = {"num_ports", PSTAT_NUM_PORTS, (vf) ps_get_num_ports}; +static void +ps_get_exe (struct proc_stat *ps, char **exe_p, int *exe_len_p) +{ + *exe_p = proc_stat_exe (ps); + *exe_len_p = proc_stat_exe_len (ps); +} +const struct ps_getter ps_exe_getter = +{"exe", PSTAT_EXE, ps_get_exe}; /* ---------------------------------------------------------------- */ /* some printing functions */ @@ -1166,6 +1174,8 @@ static const struct ps_fmt_spec specs[] = &ps_zero_fills_getter, ps_emit_int, ps_cmp_ints, ps_nominal_zint}, {"Ports", 0, -5, -1, 0, &ps_num_ports_getter, ps_emit_int, ps_cmp_ints, 0}, + {"Exe", 0, 0, -1, 0, + &ps_exe_getter, ps_emit_string, ps_cmp_strings,ps_nominal_string}, {0} }; diff --git a/proc/info.c b/proc/info.c index 3c1bf6d3..6ab9f3fa 100644 --- a/proc/info.c +++ b/proc/info.c @@ -24,6 +24,7 @@ #include <sys/mman.h> #include <hurd/hurd_types.h> #include <stdlib.h> +#include <stdio.h> #include <errno.h> #include <string.h> #include <sys/resource.h> @@ -1017,3 +1018,43 @@ S_proc_getnports (struct proc *callerp, return err; } + +/* Implement proc_set_path as described in <hurd/process.defs>. */ +kern_return_t +S_proc_set_exe (struct proc *p, + char *path) +{ + char *copy; + + if (!p) + return EOPNOTSUPP; + + copy = strdup(path); + if (! copy) + return ENOMEM; + + free(p->exe); + p->exe = copy; + return 0; +} + +/* Implement proc_get_path as described in <hurd/process.defs>. */ +kern_return_t +S_proc_get_exe (struct proc *callerp, + pid_t pid, + char *path) +{ + struct proc *p = pid_find (pid); + + /* No need to check CALLERP here; we don't use it. */ + + if (!p) + return ESRCH; + + if (p->exe) + snprintf (path, 1024 /* XXX */, "%s", p->exe); + else + path[0] = 0; + return 0; +} + @@ -223,6 +223,8 @@ S_proc_child (struct proc *parentp, childp->start_code = parentp->start_code; childp->end_code = parentp->end_code; } + if (! childp->exe && parentp->exe) + childp->exe = strdup (parentp->exe); if (MACH_PORT_VALID (parentp->p_task_namespace)) { @@ -860,6 +862,8 @@ process_has_exited (struct proc *p) if (!--p->p_login->l_refcnt) free (p->p_login); + free (p->exe); + p->exe = NULL; ids_rele (p->p_id); diff --git a/proc/proc.h b/proc/proc.h index b33845d9..a974f629 100644 --- a/proc/proc.h +++ b/proc/proc.h @@ -68,6 +68,7 @@ struct proc pthread_cond_t p_wakeup; /* Miscellaneous information */ + char *exe; /* path to binary executable */ vm_address_t p_argv, p_envp; vm_address_t start_code; /* all executable segments are in this range */ vm_address_t end_code; diff --git a/procfs/process.c b/procfs/process.c index ece37b70..59653b24 100644 --- a/procfs/process.c +++ b/procfs/process.c @@ -95,6 +95,19 @@ static int args_filename_length (const char *name) /* Actual content generators */ static ssize_t +process_file_gc_exe (struct proc_stat *ps, char **contents) +{ + if (proc_stat_exe_len (ps) == 0) + { + *contents = "-"; + return 1; + } + + *contents = proc_stat_exe(ps); + return proc_stat_exe_len(ps); +} + +static ssize_t process_file_gc_cmdline (struct proc_stat *ps, char **contents) { *contents = proc_stat_args(ps); @@ -410,6 +423,14 @@ process_file_make_node (void *dir_hook, const void *entry_hook) return np; } +static struct node * +process_file_symlink_make_node (void *dir_hook, const void *entry_hook) +{ + struct node *np = process_file_make_node (dir_hook, entry_hook); + if (np) procfs_node_chtype (np, S_IFLNK); + return np; +} + /* Stat needs its own constructor in order to set its mode according to the --stat-mode command-line option. */ static struct node * @@ -425,6 +446,17 @@ process_stat_make_node (void *dir_hook, const void *entry_hook) static struct procfs_dir_entry entries[] = { { + .name = "exe", + .hook = & (struct process_file_desc) { + .get_contents = process_file_gc_exe, + .needs = PSTAT_EXE, + .no_cleanup = 1, + }, + .ops = { + .make_node = process_file_symlink_make_node, + }, + }, + { .name = "cmdline", .hook = & (struct process_file_desc) { .get_contents = process_file_gc_cmdline, diff --git a/startup/startup.c b/startup/startup.c index 81a67716..9a06f7c2 100644 --- a/startup/startup.c +++ b/startup/startup.c @@ -832,6 +832,7 @@ launch_core_servers (void) assert_perror_backtrace (err); err = proc_mark_exec (procserver); assert_perror_backtrace (err); + proc_set_exe (procserver, "/hurd/startup"); /* Declare that the filesystem and auth are our children. */ err = proc_child (procserver, fstask); @@ -845,6 +846,7 @@ launch_core_servers (void) assert_perror_backtrace (err); err = proc_mark_exec (authproc); assert_perror_backtrace (err); + proc_set_exe (authproc, "/hurd/auth"); err = install_as_translator (); if (err) @@ -883,6 +885,7 @@ launch_core_servers (void) { proc_mark_important (procproc); proc_mark_exec (procproc); + proc_set_exe (procproc, "/hurd/proc"); mach_port_deallocate (mach_task_self (), procproc); } @@ -898,6 +901,7 @@ launch_core_servers (void) assert_perror_backtrace (err); err = proc_mark_exec (fsproc); assert_perror_backtrace (err); + proc_set_exe (fsproc, "fs"); fprintf (stderr, ".\n"); @@ -1045,6 +1049,8 @@ frob_kernel_process (void) err = record_essential_task ("kernel", task); assert_perror_backtrace (err); + proc_set_exe (proc, "kernel"); + err = task_get_bootstrap_port (task, &kbs); assert_perror_backtrace (err); if (kbs == MACH_PORT_NULL) @@ -1455,6 +1461,7 @@ S_startup_essential_task (mach_port_t server, mach_port_t execproc; proc_task2proc (procserver, task, &execproc); proc_mark_important (execproc); + proc_set_exe (execproc, "/hurd/exec"); } else if (!strcmp (name, "proc")) procinit = 1; |