diff options
Diffstat (limited to 'process.c')
-rw-r--r-- | process.c | 267 |
1 files changed, 138 insertions, 129 deletions
@@ -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; } |