summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2018-01-08 23:00:37 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2018-01-08 23:00:37 +0100
commit104f3121f8005b426d4df77b2420cfe5837033d1 (patch)
tree34bb93d3796e7c45dc1c67a5d40fb3bd1604ad9f
parent9d3ba19ddc56ad929f673af23eb87ab07ae30631 (diff)
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.c3
-rw-r--r--hurd/process.defs12
-rw-r--r--libps/procstat.c17
-rw-r--r--libps/ps.h11
-rw-r--r--libps/spec.c10
-rw-r--r--proc/info.c41
-rw-r--r--proc/mgt.c4
-rw-r--r--proc/proc.h1
-rw-r--r--procfs/process.c32
-rw-r--r--startup/startup.c7
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. */
diff --git a/libps/ps.h b/libps/ps.h
index 3ee142d0..2725b1f4 100644
--- a/libps/ps.h
+++ b/libps/ps.h
@@ -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;
+}
+
diff --git a/proc/mgt.c b/proc/mgt.c
index 354f3784..d92bf528 100644
--- a/proc/mgt.c
+++ b/proc/mgt.c
@@ -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;