summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremie Koenig <jk@jk.fr.eu.org>2010-08-21 09:26:09 +0000
committerJeremie Koenig <jk@jk.fr.eu.org>2010-08-30 14:19:08 +0200
commit1f1661d6a5b6f22acb48460b5304e29af2a0a554 (patch)
tree0aa7eb5eb5838df4e946cb7317f3cc2f18b30eba
parent086569ee636d91a820aa23031dda3cb74bab9505 (diff)
Use libps and enhance [pid]/stat
* Makefile: Add libps to the $(LIBS). * proclist.c, proclist.h: Embed the proc server port in a ps_context structure. (proclist_make_node): Change to prototype to allow for the possibility of error. Rename to proclist_create_node to reflect the change and non-triviality. * process.c, process.h: Revamp. Use a full-blown procstat structure instead of just the procinfo fetched from the process server. Use the additional data to complement [pid]/stat. (process_lookup_pid): Get a ps_context structure instead of a port to the process server. * main.c (root_make_node): Convert to the new interface for proclist_create_node.
-rw-r--r--Makefile2
-rw-r--r--main.c7
-rw-r--r--process.c267
-rw-r--r--process.h8
-rw-r--r--procfs.c2
-rw-r--r--proclist.c35
-rw-r--r--proclist.h2
7 files changed, 164 insertions, 159 deletions
diff --git a/Makefile b/Makefile
index 97a61ed..48013f9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
TARGET = procfs
OBJS = procfs.o netfs.o procfs_file.o procfs_dir.o \
process.o proclist.o dircat.o main.o
-LIBS = -lnetfs
+LIBS = -lnetfs -lps
CC = gcc
CFLAGS = -Wall -g
diff --git a/main.c b/main.c
index 1560281..75e1cda 100644
--- a/main.c
+++ b/main.c
@@ -25,16 +25,17 @@ root_make_node (struct node **np)
/* We never have two root nodes alive simultaneously, so it's ok to
have this as static data. */
static struct node *root_dirs[3];
+ error_t err;
root_dirs[0] = procfs_dir_make_node (static_entries, NULL, NULL);
if (! root_dirs[0])
return ENOMEM;
- root_dirs[1] = proclist_make_node (getproc ());
- if (! root_dirs[1])
+ err = proclist_create_node (getproc (), &root_dirs[1]);
+ if (err)
{
netfs_nrele (root_dirs[0]);
- return ENOMEM;
+ return err;
}
root_dirs[2] = NULL;
diff --git a/process.c b/process.c
index 2b89ef8..a1cc0f6 100644
--- a/process.c
+++ b/process.c
@@ -1,100 +1,75 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <hurd/process.h>
+#include <hurd/resource.h>
+#include <mach/vm_param.h>
+#include <ps.h>
#include "procfs.h"
#include "procfs_dir.h"
#include "process.h"
+
+/* Implementations for the process_file_desc.get_contents callback. */
-struct process_node {
- process_t procserv;
- pid_t pid;
- struct procinfo info;
-};
-
-
-/* The proc_getprocargs() and proc_getprocenv() calls have the same
- prototype and we use them in the same way; namely, publish the data
- they return as-is. We take advantage of this to have common code and
- use a function pointer as the procfs_dir "entry hook" to choose the
- call to use on a file by file basis. */
-
-struct process_argz_node
+static char *
+process_file_gc_cmdline (struct proc_stat *ps, size_t *len)
{
- struct process_node pn;
- error_t (*getargz) (process_t, pid_t, void **, mach_msg_type_number_t *);
-};
+ *len = proc_stat_args_len(ps);
+ return proc_stat_args(ps);
+}
-static error_t
-process_argz_get_contents (void *hook, void **contents, size_t *contents_len)
+static char *
+process_file_gc_environ (struct proc_stat *ps, size_t *len)
{
- struct process_argz_node *pz = hook;
- error_t err;
-
- *contents_len = 0;
- err = pz->getargz (pz->pn.procserv, pz->pn.pid, contents, contents_len);
- if (err)
- return EIO;
-
- return 0;
+ *len = proc_stat_args_len(ps);
+ return proc_stat_args(ps);
}
-static struct node *
-process_argz_make_node (void *dir_hook, void *entry_hook)
+static char state_char (struct proc_stat *ps)
{
- static const struct procfs_node_ops ops = {
- .get_contents = process_argz_get_contents,
- .cleanup_contents = procfs_cleanup_contents_with_vm_deallocate,
- .cleanup = free,
- };
- struct process_argz_node *zn;
-
- zn = malloc (sizeof *zn);
- if (! zn)
- return NULL;
+ int i;
- memcpy (&zn->pn, dir_hook, sizeof zn->pn);
- zn->getargz = entry_hook;
+ for (i = 0; (1 << i) & (PSTAT_STATE_P_STATES | PSTAT_STATE_T_STATES); i++)
+ if (proc_stat_state (ps) & (1 << i))
+ return proc_stat_state_tags[i];
- return procfs_make_node (&ops, zn);
+ return '?';
}
-/* The other files don't need any information besides the data in struct
- process_node. Furthermore, their contents don't have any nul byte.
- Consequently, we use a simple "multiplexer" based on the information
- below. */
-
-struct process_file_node
+static long int sc_tv (time_value_t tv)
{
- struct process_node pn;
- error_t (*get_contents) (struct process_node *pn, char **contents);
-};
+ double usecs = ((double) tv.seconds) * 1000000 + tv.microseconds;
+ return usecs * sysconf(_SC_CLK_TCK) / 1000000;
+}
-static char mapstate (int hurd_state)
+static long long int jiff_tv (time_value_t tv)
{
- return '?';
+ double usecs = ((double) tv.seconds) * 1000000 + tv.microseconds;
+ /* Let's say a jiffy is 1/100 of a second.. */
+ return usecs * 100 / 1000000;
}
-static error_t
-process_file_gc_stat (struct process_node *pn, char **contents)
+static char *
+process_file_gc_stat (struct proc_stat *ps, size_t *len)
{
- char *argz;
- size_t argz_len;
- int len;
-
- argz = NULL, argz_len = 0;
- proc_getprocargs(pn->procserv, pn->pid, &argz, &argz_len);
-
- len = asprintf (contents,
+ struct procinfo *pi = proc_stat_proc_info (ps);
+ task_basic_info_t tbi = proc_stat_task_basic_info (ps);
+ thread_basic_info_t thbi = proc_stat_thread_basic_info (ps);
+ char *contents;
+
+ /* See proc(5) for more information about the contents of each field for the
+ Linux procfs. */
+ *len = asprintf (&contents,
"%d (%s) %c " /* pid, command, state */
"%d %d %d " /* ppid, pgid, session */
"%d %d " /* controling tty stuff */
"%u " /* flags, as defined by <linux/sched.h> */
"%lu %lu %lu %lu " /* page fault counts */
"%lu %lu %ld %ld " /* user/sys times, in sysconf(_SC_CLK_TCK) */
- "%ld %ld " /* scheduler params (priority, nice) */
- "%ld %ld " /* number of threads, [obsolete] */
+ "%d %d " /* scheduler params (priority, nice) */
+ "%d %ld " /* number of threads, [obsolete] */
"%llu " /* start time since boot (jiffies) */
- "%lu %ld %lu " /* virtual size, rss, rss limit */
+ "%lu %ld %lu " /* virtual size (bytes), rss (pages), rss lim */
"%lu %lu %lu %lu %lu " /* some vm addresses (code, stack, sp, pc) */
"%lu %lu %lu %lu " /* pending, blocked, ignored and caught sigs */
"%lu " /* wait channel */
@@ -104,44 +79,71 @@ process_file_gc_stat (struct process_node *pn, char **contents)
"%u %u " /* RT priority and policy */
"%llu " /* aggregated block I/O delay */
"\n",
- pn->pid, argz ?: "", mapstate (pn->info.state),
- pn->info.ppid, pn->info.pgrp, pn->info.session,
- 0, 0,
- 0,
- 0L, 0L, 0L, 0L,
- 0L, 0L, 0L, 0L,
- 0L, 0L,
- 0L, 0L,
- 0LL,
- 0L, 0L, 0L,
+ proc_stat_pid (ps), proc_stat_args (ps), state_char (ps),
+ pi->ppid, pi->pgrp, pi->session,
+ 0, 0, /* no such thing as a major:minor for ctty */
+ 0, /* no such thing as CLONE_* flags on Hurd */
+ 0L, 0L, 0L, 0L, /* TASK_EVENTS_INFO is unavailable on GNU Mach */
+ sc_tv (thbi->user_time), sc_tv (thbi->system_time),
+ 0L, 0L, /* cumulative time for children */
+ MACH_PRIORITY_TO_NICE(thbi->base_priority) + 20,
+ MACH_PRIORITY_TO_NICE(thbi->base_priority),
+ pi->nthreads, 0L,
+ jiff_tv (thbi->creation_time), /* FIXME: ... since boot */
+ (long unsigned int) tbi->virtual_size,
+ (long unsigned int) tbi->resident_size / PAGE_SIZE, 0L,
0L, 0L, 0L, 0L, 0L,
0L, 0L, 0L, 0L,
- 0L,
+ (long unsigned int) proc_stat_thread_rpc (ps), /* close enough */
0L, 0L,
0,
0,
0, 0,
0LL);
- vm_deallocate (mach_task_self (), (vm_address_t) argz, argz_len);
+ return len >= 0 ? contents : NULL;
+}
- if (len < 0)
- return ENOMEM;
- return 0;
-}
+/* Describes a file in a process directory. This is used as an "entry hook"
+ * for our procfs_dir entry table, passed to process_file_make_node. */
+struct process_file_desc
+{
+ /* The proc_stat information required to get the contents of this file. */
+ ps_flags_t needs;
+
+ /* Once we have acquired the necessary information, there can be only
+ memory allocation errors, hence this simplified signature. */
+ char *(*get_contents) (struct proc_stat *ps, size_t *len);
+
+ /* The cmdline and environ contents don't need any cleaning since they are
+ part of a proc_stat structure. */
+ int no_cleanup;
+};
+
+/* Information associated to an actual file node. */
+struct process_file_node
+{
+ const struct process_file_desc *desc;
+ struct proc_stat *ps;
+};
static error_t
process_file_get_contents (void *hook, void **contents, size_t *contents_len)
{
- struct process_file_node *fn = hook;
+ struct process_file_node *file = hook;
error_t err;
- err = fn->get_contents (&fn->pn, (char **) contents);
+ err = proc_stat_set_flags (file->ps, file->desc->needs);
if (err)
- return err;
+ return EIO;
+ if ((proc_stat_flags (file->ps) & file->desc->needs) != file->desc->needs)
+ return EIO;
+
+ *contents = file->desc->get_contents (file->ps, contents_len);
+ if (! *contents)
+ return ENOMEM;
- *contents_len = strlen (*contents);
return 0;
}
@@ -153,68 +155,75 @@ process_file_make_node (void *dir_hook, void *entry_hook)
.cleanup_contents = procfs_cleanup_contents_with_free,
.cleanup = free,
};
- struct process_file_node *fn;
+ static const struct procfs_node_ops ops_no_cleanup = {
+ .get_contents = process_file_get_contents,
+ .cleanup = free,
+ };
+ struct process_file_node *f;
- fn = malloc (sizeof *fn);
- if (! fn)
+ f = malloc (sizeof *f);
+ if (! f)
return NULL;
- memcpy (&fn->pn, dir_hook, sizeof fn->pn);
- fn->get_contents = entry_hook;
+ f->desc = entry_hook;
+ f->ps = dir_hook;
- return procfs_make_node (&ops, fn);
+ return procfs_make_node (f->desc->no_cleanup ? &ops_no_cleanup : &ops, f);
}
-static struct node *
-process_make_node (process_t procserv, pid_t pid, const struct procinfo *info)
-{
- static const struct procfs_dir_entry entries[] = {
- { "cmdline", process_argz_make_node, proc_getprocargs, },
- { "environ", process_argz_make_node, proc_getprocenv, },
- { "stat", process_file_make_node, process_file_gc_stat, },
- { NULL, }
- };
- struct process_node *pn;
- struct node *np;
-
- pn = malloc (sizeof *pn);
- if (! pn)
- return NULL;
-
- pn->procserv = procserv;
- pn->pid = pid;
- memcpy (&pn->info, info, sizeof pn->info);
-
- np = procfs_dir_make_node (entries, pn, process_cleanup);
- np->nn_stat.st_uid = pn->info.owner;
-
- return np;
-}
+static struct procfs_dir_entry entries[] = {
+ {
+ .name = "cmdline",
+ .make_node = process_file_make_node,
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_cmdline,
+ .needs = PSTAT_ARGS,
+ .no_cleanup = 1,
+ },
+ },
+ {
+ .name = "environ",
+ .make_node = process_file_make_node,
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_environ,
+ .needs = PSTAT_ENV,
+ .no_cleanup = 1,
+ },
+ },
+ {
+ .name = "stat",
+ .make_node = process_file_make_node,
+ .hook = & (struct process_file_desc) {
+ .get_contents = process_file_gc_stat,
+ .needs = PSTAT_PID | PSTAT_ARGS | PSTAT_STATE | PSTAT_PROC_INFO
+ | PSTAT_TASK | PSTAT_TASK_BASIC | PSTAT_THREAD_BASIC
+ | PSTAT_THREAD_WAIT,
+ },
+ },
+ {}
+};
error_t
-process_lookup_pid (process_t procserv, pid_t pid, struct node **np)
+process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np)
{
- procinfo_t info;
- size_t info_sz;
- data_t tw;
- size_t tw_sz;
- int flags;
+ struct proc_stat *ps;
error_t err;
- tw_sz = info_sz = 0, flags = 0;
- err = proc_getprocinfo (procserv, pid, &flags, &info, &info_sz, &tw, &tw_sz);
+ err = _proc_stat_create (pid, pc, &ps);
if (err == ESRCH)
return ENOENT;
if (err)
return EIO;
- assert (info_sz * sizeof *info >= sizeof (struct procinfo));
- *np = process_make_node (procserv, pid, (struct procinfo *) info);
- vm_deallocate (mach_task_self (), (vm_address_t) info, info_sz);
+ err = proc_stat_set_flags (ps, PSTAT_OWNER_UID);
+ if (err || ! (proc_stat_flags (ps) & PSTAT_OWNER_UID))
+ return EIO;
+ *np = procfs_dir_make_node (entries, ps, (void (*)(void *)) _proc_stat_free);
if (! *np)
return ENOMEM;
+ (*np)->nn_stat.st_uid = proc_stat_owner_uid (ps);
return 0;
}
diff --git a/process.h b/process.h
index abdaaa3..8c2ee63 100644
--- a/process.h
+++ b/process.h
@@ -1,8 +1,8 @@
-#include <hurd.h>
+#include <ps.h>
-/* Create a node for a directory representing information available at
- the proc server PROC for the given PID. On success, returns the
+/* Create a node for a directory representing the given PID, as published by
+ the proc server refrenced by the libps context PC. On success, returns the
newly created node in *NP. */
error_t
-process_lookup_pid (process_t proc, pid_t pid, struct node **np);
+process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np);
diff --git a/procfs.c b/procfs.c
index 4cce46b..0a235a7 100644
--- a/procfs.c
+++ b/procfs.c
@@ -87,7 +87,7 @@ procfs_make_ino (struct node *np, const char *filename)
jrand48 (x);
}
- return jrand48 (x);
+ return (unsigned long) jrand48 (x);
}
error_t procfs_get_contents (struct node *np, void **data, size_t *data_len)
diff --git a/proclist.c b/proclist.c
index 94a7a04..56a3fdf 100644
--- a/proclist.c
+++ b/proclist.c
@@ -3,27 +3,23 @@
#include <string.h>
#include <mach.h>
#include <hurd/process.h>
+#include <ps.h>
#include "procfs.h"
#include "process.h"
#define PID_STR_SIZE (3 * sizeof (pid_t) + 1)
-struct proclist_node
-{
- process_t process;
-};
-
static error_t
proclist_get_contents (void *hook, void **contents, size_t *contents_len)
{
- struct proclist_node *pl = hook;
+ struct ps_context *pc = hook;
pidarray_t pids;
mach_msg_type_number_t num_pids;
error_t err;
int i;
num_pids = 0;
- err = proc_getallpids (pl->process, &pids, &num_pids);
+ err = proc_getallpids (pc->server, &pids, &num_pids);
if (err)
return EIO;
@@ -48,7 +44,7 @@ proclist_get_contents (void *hook, void **contents, size_t *contents_len)
static error_t
proclist_lookup (void *hook, const char *name, struct node **np)
{
- struct proclist_node *pl = hook;
+ struct ps_context *pc = hook;
char *endp;
pid_t pid;
@@ -63,28 +59,27 @@ proclist_lookup (void *hook, const char *name, struct node **np)
if (*endp)
return ENOENT;
- return process_lookup_pid (pl->process, pid, np);
+ return process_lookup_pid (pc, pid, np);
}
-struct node *
-proclist_make_node (process_t process)
+error_t
+proclist_create_node (process_t procserv, struct node **np)
{
static const struct procfs_node_ops ops = {
.get_contents = proclist_get_contents,
.lookup = proclist_lookup,
.cleanup_contents = procfs_cleanup_contents_with_free,
- .cleanup = free,
+ .cleanup = (void (*)(void *)) ps_context_free,
.enable_refresh_hack_and_break_readdir = 1,
};
- struct proclist_node *pl;
-
- pl = malloc (sizeof *pl);
- if (! pl)
- return NULL;
+ struct ps_context *pc;
+ error_t err;
- memset (pl, 0, sizeof *pl);
- pl->process = process;
+ err = ps_context_create (procserv, &pc);
+ if (err)
+ return err;
- return procfs_make_node (&ops, pl);
+ *np = procfs_make_node (&ops, pc);
+ return 0;
}
diff --git a/proclist.h b/proclist.h
index a766d50..1c7ab08 100644
--- a/proclist.h
+++ b/proclist.h
@@ -1,2 +1,2 @@
#include <hurd/hurd_types.h>
-struct node *proclist_make_node (process_t process);
+error_t proclist_create_node (process_t procserv, struct node **np);