From 2717c43bca6f920c4d3b0909c33bf3c1f76a70a9 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Sat, 21 Aug 2010 18:08:17 +0000 Subject: New root files: version, uptime, stat * rootdir.c, rootdir.h: New files. * main.c: Use rootdir_create_node. * Makefile: Add the rootdir module. --- rootdir.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 rootdir.c (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c new file mode 100644 index 00000000..fb48b932 --- /dev/null +++ b/rootdir.c @@ -0,0 +1,159 @@ +#include +#include +#include +#include +#include +#include "procfs.h" +#include "procfs_dir.h" + +/* This implements a directory node with the static files in /proc */ + +#define INIT_PID 1 + +static error_t +get_boottime (struct ps_context *pc, struct timeval *tv) +{ + struct proc_stat *ps; + error_t err; + + err = _proc_stat_create (INIT_PID, pc, &ps); + if (err) + return err; + + err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC); + if (err || !(proc_stat_flags (ps) & PSTAT_TASK_BASIC)) + err = EIO; + + if (! err) + { + task_basic_info_t tbi = proc_stat_task_basic_info (ps); + tv->tv_sec = tbi->creation_time.seconds; + tv->tv_usec = tbi->creation_time.microseconds; + } + + _proc_stat_free (ps); + return err; +} + +static error_t +rootdir_gc_version (void *hook, void **contents, size_t *contents_len) +{ + struct utsname uts; + int r; + + r = uname (&uts); + if (r < 0) + return errno; + + *contents_len = asprintf ((char **) contents, + "Linux version 2.6.1 (%s %s %s %s)\n", + uts.sysname, uts.release, uts.version, uts.machine); + + return *contents_len >= 0 ? 0 : ENOMEM; +} + +/* Uptime -- we use the start time of init to deduce it. This is probably a bit + fragile, as any clock update will make the result inaccurate. */ +static error_t +rootdir_gc_uptime (void *hook, void **contents, size_t *contents_len) +{ + struct timeval time, boottime; + double up_secs; + error_t err; + + err = gettimeofday (&time, NULL); + if (err < 0) + return errno; + + err = get_boottime (hook, &boottime); + if (err) + return err; + + timersub (&time, &boottime, &time); + up_secs = time.tv_sec + time.tv_usec / 1000000.; + + /* The second field is the total idle time. As far as I know we don't + keep track of it. */ + *contents_len = asprintf ((char **) contents, "%.2lf %.2lf\n", up_secs, 0.); + + return *contents_len >= 0 ? 0 : ENOMEM; +} + +static error_t +rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) +{ + struct timeval boottime; + struct vm_statistics vmstats; + error_t err; + + err = get_boottime (hook, &boottime); + if (err) + return err; + + err = vm_statistics (mach_task_self (), &vmstats); + if (err) + return EIO; + + *contents_len = asprintf ((char **) contents, + /* Does Mach keeps track of any of this? */ + "cpu 0 0 0 0 0 0 0 0 0\n" + "cpu0 0 0 0 0 0 0 0 0 0\n" + "intr 0\n" + /* This we know. */ + "page %d %d\n" + "btime %lu\n", + vmstats.pageins, vmstats.pageouts, + boottime.tv_sec); + + return *contents_len >= 0 ? 0 : ENOMEM; +} + +static struct node * +rootdir_file_make_node (void *dir_hook, void *entry_hook) +{ + return procfs_make_node (entry_hook, dir_hook); +} + +static struct procfs_dir_entry rootdir_entries[] = { + { + .name = "version", + .make_node = rootdir_file_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_version, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, + { + .name = "uptime", + .make_node = rootdir_file_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_uptime, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, + { + .name = "stat", + .make_node = rootdir_file_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_stat, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, + {} +}; + +error_t +rootdir_create_node (struct node **np) +{ + struct ps_context *pc; + error_t err; + + err = ps_context_create (getproc (), &pc); + if (err) + return err; + + *np = procfs_dir_make_node (rootdir_entries, pc, + (void (*)(void *)) ps_context_free); + return 0; +} + -- cgit v1.2.3 From efb8515465dcb03526a35bf87b549cac97bbab8c Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Sat, 21 Aug 2010 19:18:59 +0000 Subject: Add loadavg * rootdir.c: Add the root file "loadavg". --- rootdir.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index fb48b932..0985b63b 100644 --- a/rootdir.c +++ b/rootdir.c @@ -108,6 +108,28 @@ rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) return *contents_len >= 0 ? 0 : ENOMEM; } +static error_t +rootdir_gc_loadavg (void *hook, void **contents, size_t *contents_len) +{ + host_load_info_data_t hli; + mach_msg_type_number_t cnt; + error_t err; + + cnt = HOST_LOAD_INFO_COUNT; + err = host_info (mach_host_self (), HOST_LOAD_INFO, (host_info_t) &hli, &cnt); + if (err) + return err; + + assert (cnt == HOST_LOAD_INFO_COUNT); + *contents_len = asprintf ((char **) contents, + "%.2f %.2f %.2f 1/0 0\n", + hli.avenrun[0] / (double) LOAD_SCALE, + hli.avenrun[1] / (double) LOAD_SCALE, + hli.avenrun[2] / (double) LOAD_SCALE); + + return *contents_len >= 0 ? 0 : ENOMEM; +} + static struct node * rootdir_file_make_node (void *dir_hook, void *entry_hook) { @@ -139,6 +161,14 @@ static struct procfs_dir_entry rootdir_entries[] = { .cleanup_contents = procfs_cleanup_contents_with_free, }, }, + { + .name = "loadavg", + .make_node = rootdir_file_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_loadavg, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, {} }; -- cgit v1.2.3 From aa3bac054364aa2d3614ded28df4980639184319 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 00:55:11 +0000 Subject: Add a fake "self" symlink * rootdir.c: Add a fake "self" symlink which always points to init. --- rootdir.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index 0985b63b..79928446 100644 --- a/rootdir.c +++ b/rootdir.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "procfs.h" #include "procfs_dir.h" @@ -130,12 +131,30 @@ rootdir_gc_loadavg (void *hook, void **contents, size_t *contents_len) return *contents_len >= 0 ? 0 : ENOMEM; } +static error_t +rootdir_gc_fakeself (void *hook, void **contents, size_t *contents_len) +{ + *contents = "1"; + *contents_len = strlen (*contents); + return 0; +} + + static struct node * rootdir_file_make_node (void *dir_hook, void *entry_hook) { return procfs_make_node (entry_hook, dir_hook); } +static struct node * +rootdir_symlink_make_node (void *dir_hook, void *entry_hook) +{ + struct node *np = procfs_make_node (entry_hook, dir_hook); + if (np) + procfs_node_chtype (np, S_IFLNK); + return np; +} + static struct procfs_dir_entry rootdir_entries[] = { { .name = "version", @@ -169,6 +188,13 @@ static struct procfs_dir_entry rootdir_entries[] = { .cleanup_contents = procfs_cleanup_contents_with_free, }, }, + { + .name = "self", + .make_node = rootdir_symlink_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_fakeself, + }, + }, {} }; -- cgit v1.2.3 From c68fc8b783804e093551d93cc1b8c10964cdaaeb Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 00:55:29 +0000 Subject: Add an empty meminfo root file * rootdir.c: Add "meminfo", empty for now. --- rootdir.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index 79928446..17fdb93a 100644 --- a/rootdir.c +++ b/rootdir.c @@ -131,6 +131,13 @@ rootdir_gc_loadavg (void *hook, void **contents, size_t *contents_len) return *contents_len >= 0 ? 0 : ENOMEM; } +static error_t +rootdir_gc_empty (void *hook, void **contents, size_t *contents_len) +{ + *contents_len = 0; + return 0; +} + static error_t rootdir_gc_fakeself (void *hook, void **contents, size_t *contents_len) { @@ -188,6 +195,13 @@ static struct procfs_dir_entry rootdir_entries[] = { .cleanup_contents = procfs_cleanup_contents_with_free, }, }, + { + .name = "meminfo", + .make_node = rootdir_file_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_empty, + }, + }, { .name = "self", .make_node = rootdir_symlink_make_node, -- cgit v1.2.3 From f9ddb679942b6f4309d05b5462fe5cbb3d0a2beb Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Sun, 22 Aug 2010 19:33:43 +0000 Subject: Play nice with the procps old_Hertz_hack * rootdir.c (rootdir_gc_uptime, rootdir_gc_stat): assume a completely idle rather than completely busy system, so that the idle seconds can be meaningfully divided by the idle jiffies by procps. --- rootdir.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index 17fdb93a..50f6e071 100644 --- a/rootdir.c +++ b/rootdir.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -74,8 +75,11 @@ rootdir_gc_uptime (void *hook, void **contents, size_t *contents_len) up_secs = time.tv_sec + time.tv_usec / 1000000.; /* The second field is the total idle time. As far as I know we don't - keep track of it. */ - *contents_len = asprintf ((char **) contents, "%.2lf %.2lf\n", up_secs, 0.); + keep track of it. However, procps uses it to compute "USER_HZ", and + proc(5) specifies that it should be equal to USER_HZ times the idle value + in ticks from /proc/stat. So we assume a completely idle system both here + and there to make that work. */ + *contents_len = asprintf ((char **) contents, "%.2lf %.2lf\n", up_secs, up_secs); return *contents_len >= 0 ? 0 : ENOMEM; } @@ -83,10 +87,15 @@ rootdir_gc_uptime (void *hook, void **contents, size_t *contents_len) static error_t rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) { - struct timeval boottime; + struct timeval boottime, time; struct vm_statistics vmstats; + unsigned long up_ticks; error_t err; + err = gettimeofday (&time, NULL); + if (err < 0) + return errno; + err = get_boottime (hook, &boottime); if (err) return err; @@ -95,14 +104,19 @@ rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) if (err) return EIO; + timersub (&time, &boottime, &time); + up_ticks = sysconf(_SC_CLK_TCK) * (time.tv_sec + time.tv_usec / 1000000.); + *contents_len = asprintf ((char **) contents, /* Does Mach keeps track of any of this? */ - "cpu 0 0 0 0 0 0 0 0 0\n" - "cpu0 0 0 0 0 0 0 0 0 0\n" + "cpu 0 0 0 %lu 0 0 0 0 0\n" + "cpu0 0 0 0 %lu 0 0 0 0 0\n" "intr 0\n" /* This we know. */ "page %d %d\n" "btime %lu\n", + up_ticks, + up_ticks, vmstats.pageins, vmstats.pageouts, boottime.tv_sec); -- cgit v1.2.3 From b3427143ae8dc628cb3748da7618700c6bd7ac9e Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Sun, 22 Aug 2010 20:17:54 +0000 Subject: Add --clk-tck to set the clock unit * main.c (argp_parser, main): Add and parse the --clk-tck option. * main.h: Publish opt_clk_tck. * process.c (sc_tc): Use the user-provided clock frequency. * rootdir.c (rootdir_gc_stat): Likewise. --- main.c | 40 +++++++++++++++++++++++++++++++++++++++- main.h | 2 ++ process.c | 3 ++- rootdir.c | 3 ++- 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 main.h (limited to 'rootdir.c') diff --git a/main.c b/main.c index 15ad60f4..a59ab47f 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,6 +8,42 @@ #include "proclist.h" #include "rootdir.h" #include "dircat.h" +#include "main.h" + +/* Command-line options */ +int opt_clk_tck; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + char *endp; + + switch (key) + { + case 'h': + opt_clk_tck = strtol (arg, &endp, 0); + if (*endp || ! *arg || opt_clk_tck <= 0) + error (1, 0, "--clk-tck: HZ should be a positive integer"); + break; + } + + return 0; +} + +struct argp argp = { + .options = (struct argp_option []) { + { "clk-tck", 'h', "HZ", 0, + "Unit used for the values expressed in system clock ticks " + "(default: sysconf(_SC_CLK_TCK))" }, + {} + }, + .parser = argp_parser, + .doc = "A virtual filesystem emulating the Linux procfs.", + .children = (struct argp_child []) { + { &netfs_std_startup_argp, }, + {} + }, +}; error_t root_make_node (struct node **np) @@ -43,7 +80,8 @@ int main (int argc, char **argv) { mach_port_t bootstrap; - argp_parse (&netfs_std_startup_argp, argc, argv, 0, 0, 0); + opt_clk_tck = sysconf(_SC_CLK_TCK); + argp_parse (&argp, argc, argv, 0, 0, 0); task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) diff --git a/main.h b/main.h new file mode 100644 index 00000000..4b2ef9a1 --- /dev/null +++ b/main.h @@ -0,0 +1,2 @@ +/* Startup options */ +extern int opt_clk_tck; diff --git a/process.c b/process.c index 8955cf40..65f0e503 100644 --- a/process.c +++ b/process.c @@ -8,6 +8,7 @@ #include "procfs.h" #include "procfs_dir.h" #include "process.h" +#include "main.h" /* Implementations for the process_file_desc.get_contents callback. */ @@ -39,7 +40,7 @@ static char state_char (struct proc_stat *ps) static long int sc_tv (time_value_t tv) { double usecs = ((double) tv.seconds) * 1000000 + tv.microseconds; - return usecs * sysconf(_SC_CLK_TCK) / 1000000; + return usecs * opt_clk_tck / 1000000; } static long long int jiff_tv (time_value_t tv) diff --git a/rootdir.c b/rootdir.c index 50f6e071..1d9c083c 100644 --- a/rootdir.c +++ b/rootdir.c @@ -7,6 +7,7 @@ #include #include "procfs.h" #include "procfs_dir.h" +#include "main.h" /* This implements a directory node with the static files in /proc */ @@ -105,7 +106,7 @@ rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) return EIO; timersub (&time, &boottime, &time); - up_ticks = sysconf(_SC_CLK_TCK) * (time.tv_sec + time.tv_usec / 1000000.); + up_ticks = opt_clk_tck * (time.tv_sec + time.tv_usec / 1000000.); *contents_len = asprintf ((char **) contents, /* Does Mach keeps track of any of this? */ -- cgit v1.2.3 From 4665f087fde174a9de3e1c3f3de090dd4bfa85e0 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Sun, 22 Aug 2010 21:23:36 +0000 Subject: Add a fake-self option to control the self symlink * main.c (argp_parse, main): Add the --fake-self option. * main.h: Publish it. * rootdir.c (rootdir_gc_fakeself, rootdir_entries, rootdir_create_node): Use it. --- main.c | 17 +++++++++++++++++ main.h | 1 + rootdir.c | 30 +++++++++++++++++------------- 3 files changed, 35 insertions(+), 13 deletions(-) (limited to 'rootdir.c') diff --git a/main.c b/main.c index 09cffc76..26f5248f 100644 --- a/main.c +++ b/main.c @@ -13,6 +13,7 @@ /* Command-line options */ int opt_clk_tck; mode_t opt_stat_mode; +pid_t opt_fake_self; static error_t argp_parser (int key, char *arg, struct argp_state *state) @@ -32,6 +33,17 @@ argp_parser (int key, char *arg, struct argp_state *state) if (*endp || ! *arg || opt_stat_mode & ~07777) error (1, 0, "--stat-mode: MODE should be an octal mode"); break; + + case 'S': + if (arg) + { + opt_fake_self = strtol (arg, &endp, 0); + if (*endp || ! *arg) + error (1, 0, "--fake-self: PID must be an integer"); + } + else + opt_fake_self = 1; + break; } return 0; @@ -48,6 +60,10 @@ struct argp argp = { "You can use this option to override its mode to be more permissive " "for compatibility purposes. " "(default: 0400)" }, + { "fake-self", 'S', "PID", OPTION_ARG_OPTIONAL, + "Provide a fake \"self\" symlink to the given PID, for compatibility " + "purposes. If PID is omitted, \"self\" will point to init. " + "(default: no self link)" }, {} }, .parser = argp_parser, @@ -95,6 +111,7 @@ int main (int argc, char **argv) opt_clk_tck = sysconf(_SC_CLK_TCK); opt_stat_mode = 0400; + opt_fake_self = -1; argp_parse (&argp, argc, argv, 0, 0, 0); task_get_bootstrap_port (mach_task_self (), &bootstrap); diff --git a/main.h b/main.h index 6669d321..361380b3 100644 --- a/main.h +++ b/main.h @@ -1,3 +1,4 @@ /* Startup options */ extern int opt_clk_tck; extern mode_t opt_stat_mode; +extern pid_t opt_fake_self; diff --git a/rootdir.c b/rootdir.c index 1d9c083c..833fc150 100644 --- a/rootdir.c +++ b/rootdir.c @@ -156,9 +156,8 @@ rootdir_gc_empty (void *hook, void **contents, size_t *contents_len) static error_t rootdir_gc_fakeself (void *hook, void **contents, size_t *contents_len) { - *contents = "1"; - *contents_len = strlen (*contents); - return 0; + *contents_len = asprintf ((char **) contents, "%d", opt_fake_self); + return *contents_len >= 0 ? 0 : ENOMEM; } @@ -177,7 +176,15 @@ rootdir_symlink_make_node (void *dir_hook, void *entry_hook) return np; } -static struct procfs_dir_entry rootdir_entries[] = { +static const struct procfs_dir_entry rootdir_entries[] = { + { + .name = "self", + .make_node = rootdir_symlink_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_fakeself, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, { .name = "version", .make_node = rootdir_file_make_node, @@ -217,13 +224,6 @@ static struct procfs_dir_entry rootdir_entries[] = { .get_contents = rootdir_gc_empty, }, }, - { - .name = "self", - .make_node = rootdir_symlink_make_node, - .hook = & (struct procfs_node_ops) { - .get_contents = rootdir_gc_fakeself, - }, - }, {} }; @@ -231,14 +231,18 @@ error_t rootdir_create_node (struct node **np) { struct ps_context *pc; + const struct procfs_dir_entry *entries; error_t err; err = ps_context_create (getproc (), &pc); if (err) return err; - *np = procfs_dir_make_node (rootdir_entries, pc, - (void (*)(void *)) ps_context_free); + entries = rootdir_entries; + if (opt_fake_self < 0) + entries++; + + *np = procfs_dir_make_node (entries, pc, (void (*)(void *)) ps_context_free); return 0; } -- cgit v1.2.3 From 0ef322973a8b9dc9c0f5ba8155ad780016f3654f Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 00:52:24 +0000 Subject: Add meminfo and vmstat * rootdir.c: Add a (non-empty) meminfo and a vmstat file. --- rootdir.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 5 deletions(-) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index 833fc150..f5b43ff0 100644 --- a/rootdir.c +++ b/rootdir.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -9,7 +10,10 @@ #include "procfs_dir.h" #include "main.h" -/* This implements a directory node with the static files in /proc */ +/* This implements a directory node with the static files in /proc. + NB: the libps functions for host information return static storage; + using them would require locking and as a consequence it would be + more complicated, not simpler. */ #define INIT_PID 1 @@ -147,10 +151,83 @@ rootdir_gc_loadavg (void *hook, void **contents, size_t *contents_len) } static error_t -rootdir_gc_empty (void *hook, void **contents, size_t *contents_len) +rootdir_gc_meminfo (void *hook, void **contents, size_t *contents_len) { - *contents_len = 0; - return 0; + host_basic_info_data_t hbi; + mach_msg_type_number_t cnt; + struct vm_statistics vmstats; + error_t err; + + err = vm_statistics (mach_task_self (), &vmstats); + if (err) + return EIO; + + cnt = HOST_BASIC_INFO_COUNT; + err = host_info (mach_host_self (), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt); + if (err) + return err; + + assert (cnt == HOST_BASIC_INFO_COUNT); + *contents_len = asprintf ((char **) contents, + "MemTotal: %14lu kB\n" + "MemFree: %14lu kB\n" + "Active: %14lu kB\n" + "Inactive: %14lu kB\n" + "Mlocked: %14lu kB\n" + , + /* TODO: check that these are really 1024-bytes kBs. */ + (long unsigned) hbi.memory_size / 1024, + (long unsigned) vmstats.free_count * PAGE_SIZE / 1024, + (long unsigned) vmstats.active_count * PAGE_SIZE / 1024, + (long unsigned) vmstats.inactive_count * PAGE_SIZE / 1024, + (long unsigned) vmstats.wire_count * PAGE_SIZE / 1024); + + return *contents_len >= 0 ? 0 : ENOMEM; +} + +static error_t +rootdir_gc_vmstat (void *hook, void **contents, size_t *contents_len) +{ + host_basic_info_data_t hbi; + mach_msg_type_number_t cnt; + struct vm_statistics vmstats; + error_t err; + + err = vm_statistics (mach_task_self (), &vmstats); + if (err) + return EIO; + + cnt = HOST_BASIC_INFO_COUNT; + err = host_info (mach_host_self (), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt); + if (err) + return err; + + assert (cnt == HOST_BASIC_INFO_COUNT); + *contents_len = asprintf ((char **) contents, + "nr_free_pages %lu\n" + "nr_inactive_anon %lu\n" + "nr_active_anon %lu\n" + "nr_inactive_file %lu\n" + "nr_active_file %lu\n" + "nr_unevictable %lu\n" + "nr_mlock %lu\n" + "pgpgin %lu\n" + "pgpgout %lu\n" + "pgfault %lu\n", + (long unsigned) vmstats.free_count, + /* FIXME: how can we distinguish the anon/file pages? Maybe we can + ask the default pager how many it manages? */ + (long unsigned) vmstats.inactive_count, + (long unsigned) vmstats.active_count, + (long unsigned) 0, + (long unsigned) 0, + (long unsigned) vmstats.wire_count, + (long unsigned) vmstats.wire_count, + (long unsigned) vmstats.pageins, + (long unsigned) vmstats.pageouts, + (long unsigned) vmstats.faults); + + return *contents_len >= 0 ? 0 : ENOMEM; } static error_t @@ -221,7 +298,16 @@ static const struct procfs_dir_entry rootdir_entries[] = { .name = "meminfo", .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { - .get_contents = rootdir_gc_empty, + .get_contents = rootdir_gc_meminfo, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, + { + .name = "vmstat", + .make_node = rootdir_file_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_vmstat, + .cleanup_contents = procfs_cleanup_contents_with_free, }, }, {} -- cgit v1.2.3 From e3707dc9deb28d5144836032a54dbc028247835d Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 05:19:19 +0000 Subject: Add a global cmdline file * main.c (argp_parser, main): Add the --kernel-pid option. * main.h: Publish it. * rootdir.c (rootdir_gc_cmdline): New function. --- main.c | 11 +++++++++++ main.h | 1 + rootdir.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) (limited to 'rootdir.c') diff --git a/main.c b/main.c index 26f5248f..fee4867c 100644 --- a/main.c +++ b/main.c @@ -14,6 +14,7 @@ int opt_clk_tck; mode_t opt_stat_mode; pid_t opt_fake_self; +pid_t opt_kernel_pid; static error_t argp_parser (int key, char *arg, struct argp_state *state) @@ -44,6 +45,12 @@ argp_parser (int key, char *arg, struct argp_state *state) else opt_fake_self = 1; break; + + case 'k': + opt_kernel_pid = strtol (arg, &endp, 0); + if (*endp || ! *arg || (signed) opt_kernel_pid < 0) + error (1, 0, "--kernel-process: PID must be a positive integer"); + break; } return 0; @@ -64,6 +71,9 @@ struct argp argp = { "Provide a fake \"self\" symlink to the given PID, for compatibility " "purposes. If PID is omitted, \"self\" will point to init. " "(default: no self link)" }, + { "kernel-process", 'k', "PID", 0, + "Process identifier for the kernel, used to retreive its command line " + "(default: 2)" }, {} }, .parser = argp_parser, @@ -112,6 +122,7 @@ int main (int argc, char **argv) opt_clk_tck = sysconf(_SC_CLK_TCK); opt_stat_mode = 0400; opt_fake_self = -1; + opt_kernel_pid = 2; argp_parse (&argp, argc, argv, 0, 0, 0); task_get_bootstrap_port (mach_task_self (), &bootstrap); diff --git a/main.h b/main.h index 361380b3..6ada229a 100644 --- a/main.h +++ b/main.h @@ -2,3 +2,4 @@ extern int opt_clk_tck; extern mode_t opt_stat_mode; extern pid_t opt_fake_self; +extern pid_t opt_kernel_pid; diff --git a/rootdir.c b/rootdir.c index f5b43ff0..865342ce 100644 --- a/rootdir.c +++ b/rootdir.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "procfs.h" #include "procfs_dir.h" @@ -230,6 +231,41 @@ rootdir_gc_vmstat (void *hook, void **contents, size_t *contents_len) return *contents_len >= 0 ? 0 : ENOMEM; } +static error_t +rootdir_gc_cmdline (void *hook, void **contents, size_t *contents_len) +{ + struct ps_context *pc = hook; + struct proc_stat *ps; + error_t err; + + err = _proc_stat_create (opt_kernel_pid, pc, &ps); + if (err) + return EIO; + + err = proc_stat_set_flags (ps, PSTAT_ARGS); + if (err || ! (proc_stat_flags (ps) & PSTAT_ARGS)) + { + err = EIO; + goto out; + } + + *contents_len = proc_stat_args_len (ps); + *contents = malloc (*contents_len); + if (! *contents) + { + err = ENOMEM; + goto out; + } + + memcpy (*contents, proc_stat_args (ps), *contents_len); + argz_stringify (*contents, *contents_len, ' '); + ((char *) *contents)[*contents_len - 1] = '\n'; + +out: + _proc_stat_free (ps); + return err; +} + static error_t rootdir_gc_fakeself (void *hook, void **contents, size_t *contents_len) { @@ -310,6 +346,14 @@ static const struct procfs_dir_entry rootdir_entries[] = { .cleanup_contents = procfs_cleanup_contents_with_free, }, }, + { + .name = "cmdline", + .make_node = rootdir_file_make_node, + .hook = & (struct procfs_node_ops) { + .get_contents = rootdir_gc_cmdline, + .cleanup_contents = procfs_cleanup_contents_with_free, + }, + }, {} }; -- cgit v1.2.3 From 4deaca2ce2c4ed2c5ab53f57a7747c71126a8da7 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 09:06:01 +0000 Subject: Use a global ps_context * proclist.c, proclist.h (proclist_create_node): Use a ps_context passed by the caller; errors are no longer possible, rename to proclist_make_node and change the signature accordingly. * rootdir.c, rootdir.h (rootdir_create_node): Likewise. * main.c (main): Create the ps_context here and pass it to root_make_node. (root_make_node): Pass it to proclist_make_node and rootdir_make_node. --- main.c | 35 ++++++++++++++++++++++------------- proclist.c | 15 +++------------ proclist.h | 6 ++++-- rootdir.c | 13 +++---------- rootdir.h | 6 ++++-- 5 files changed, 36 insertions(+), 39 deletions(-) (limited to 'rootdir.c') diff --git a/main.c b/main.c index 4be506fb..91156485 100644 --- a/main.c +++ b/main.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "procfs.h" #include "proclist.h" #include "rootdir.h" @@ -94,38 +95,42 @@ struct argp argp = { }; error_t -root_make_node (struct node **np) +root_make_node (struct ps_context *pc, 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; - err = proclist_create_node (getproc (), &root_dirs[0]); - if (err) - return err; + root_dirs[0] = proclist_make_node (pc); + if (! root_dirs[0]) + goto nomem; - err = rootdir_create_node (&root_dirs[1]); - if (err) - { - netfs_nrele (root_dirs[0]); - return err; - } + root_dirs[1] = rootdir_make_node (pc); + if (! root_dirs[1]) + goto nomem; root_dirs[2] = NULL; *np = dircat_make_node (root_dirs); if (! *np) - return ENOMEM; + goto nomem; /* Since this one is not created through proc_lookup(), we have to affect an inode number to it. */ (*np)->nn_stat.st_ino = * (uint32_t *) "PROC"; return 0; + +nomem: + if (root_dirs[1]) + netfs_nrele (root_dirs[1]); + if (root_dirs[0]) + netfs_nrele (root_dirs[0]); + return ENOMEM; } int main (int argc, char **argv) { + struct ps_context *pc; mach_port_t bootstrap; error_t err; @@ -137,12 +142,16 @@ int main (int argc, char **argv) if (err) error (1, err, "Could not parse command line"); + err = ps_context_create (getproc (), &pc); + if (err) + error (1, err, "Could not create libps context"); + task_get_bootstrap_port (mach_task_self (), &bootstrap); if (bootstrap == MACH_PORT_NULL) error (1, 0, "Must be started as a translator"); netfs_init (); - err = root_make_node (&netfs_root_node); + err = root_make_node (pc, &netfs_root_node); if (err) error (1, err, "Could not create the root node"); diff --git a/proclist.c b/proclist.c index 56a3fdf9..35422a81 100644 --- a/proclist.c +++ b/proclist.c @@ -62,24 +62,15 @@ proclist_lookup (void *hook, const char *name, struct node **np) return process_lookup_pid (pc, pid, np); } -error_t -proclist_create_node (process_t procserv, struct node **np) +struct node * +proclist_make_node (struct ps_context *pc) { static const struct procfs_node_ops ops = { .get_contents = proclist_get_contents, .lookup = proclist_lookup, .cleanup_contents = procfs_cleanup_contents_with_free, - .cleanup = (void (*)(void *)) ps_context_free, .enable_refresh_hack_and_break_readdir = 1, }; - struct ps_context *pc; - error_t err; - - err = ps_context_create (procserv, &pc); - if (err) - return err; - - *np = procfs_make_node (&ops, pc); - return 0; + return procfs_make_node (&ops, pc); } diff --git a/proclist.h b/proclist.h index 1c7ab084..ce69dde3 100644 --- a/proclist.h +++ b/proclist.h @@ -1,2 +1,4 @@ -#include -error_t proclist_create_node (process_t procserv, struct node **np); +#include + +struct node * +proclist_make_node (struct ps_context *pc); diff --git a/rootdir.c b/rootdir.c index 865342ce..8062f0d3 100644 --- a/rootdir.c +++ b/rootdir.c @@ -357,22 +357,15 @@ static const struct procfs_dir_entry rootdir_entries[] = { {} }; -error_t -rootdir_create_node (struct node **np) +struct node +*rootdir_make_node (struct ps_context *pc) { - struct ps_context *pc; const struct procfs_dir_entry *entries; - error_t err; - - err = ps_context_create (getproc (), &pc); - if (err) - return err; entries = rootdir_entries; if (opt_fake_self < 0) entries++; - *np = procfs_dir_make_node (entries, pc, (void (*)(void *)) ps_context_free); - return 0; + return procfs_dir_make_node (entries, pc, NULL); } diff --git a/rootdir.h b/rootdir.h index a764b0fd..0caee258 100644 --- a/rootdir.h +++ b/rootdir.h @@ -1,2 +1,4 @@ -error_t -rootdir_create_node (struct node **np); +#include + +struct node * +rootdir_make_node (struct ps_context *pc); -- cgit v1.2.3 From 0f2bdacd6ad3dbcc905925dee12cb30918c33a11 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 11:24:29 +0000 Subject: Make contents a char* to avoid typecasts all over the place * procfs.h (procfs_cleanup_contents_with_free, procfs_cleanup_contents_with_vm_deallocate, procfs_get_contents, struct procfs_ops): Change CONTENTS from a void pointer to a char one. * dircat.c, netfs.c, process.c, procfs.c, procfs_dir.c, proclist.c, rootdir.c: Update. --- dircat.c | 4 ++-- netfs.c | 10 +++++----- process.c | 2 +- procfs.c | 10 +++++----- procfs.h | 10 +++++----- procfs_dir.c | 2 +- proclist.c | 2 +- rootdir.c | 32 ++++++++++++++++---------------- 8 files changed, 36 insertions(+), 36 deletions(-) (limited to 'rootdir.c') diff --git a/dircat.c b/dircat.c index 857ba72b..93bb2fed 100644 --- a/dircat.c +++ b/dircat.c @@ -8,7 +8,7 @@ struct dircat_node }; static error_t -dircat_get_contents (void *hook, void **contents, size_t *contents_len) +dircat_get_contents (void *hook, char **contents, size_t *contents_len) { struct dircat_node *dcn = hook; int i, sz, pos; @@ -19,7 +19,7 @@ dircat_get_contents (void *hook, void **contents, size_t *contents_len) for (i=0; dcn->dirs[i]; i++) { - void *subcon; + char *subcon; size_t sublen; err = procfs_get_contents (dcn->dirs[i], &subcon, &sublen); diff --git a/netfs.c b/netfs.c index a47861e5..6fd82a00 100644 --- a/netfs.c +++ b/netfs.c @@ -29,7 +29,7 @@ int netfs_maxsymlinks = PROCFS_MAXSYMLINKS; responsible for the operation. NP is locked. */ error_t netfs_validate_stat (struct node *np, struct iouser *cred) { - void *contents; + char *contents; size_t contents_len; error_t err; @@ -57,7 +57,7 @@ error_t netfs_attempt_read (struct iouser *cred, struct node *np, size_t contents_len; error_t err; - err = procfs_get_contents (np, (void **) &contents, &contents_len); + err = procfs_get_contents (np, &contents, &contents_len); if (err) return err; @@ -82,7 +82,7 @@ error_t netfs_attempt_readlink (struct iouser *user, struct node *np, size_t contents_len; error_t err; - err = procfs_get_contents (np, (void **) &contents, &contents_len); + err = procfs_get_contents (np, &contents, &contents_len); if (err) return err; @@ -140,7 +140,7 @@ error_t netfs_get_dirents (struct iouser *cred, struct node *dir, size_t contents_len; error_t err; - err = procfs_get_contents (dir, (void **) &contents, &contents_len); + err = procfs_get_contents (dir, &contents, &contents_len); if (err) return err; @@ -159,7 +159,7 @@ error_t netfs_get_dirents (struct iouser *cred, struct node *dir, putentries (contents, contents_len, nentries, NULL, datacnt); if (bufsize < *datacnt) { - void *n = mmap (0, *datacnt, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, 0, 0); + char *n = mmap (0, *datacnt, PROT_READ | PROT_WRITE, MAP_ANONYMOUS, 0, 0); if (n == MAP_FAILED) return ENOMEM; diff --git a/process.c b/process.c index 7f5646ae..fa795522 100644 --- a/process.c +++ b/process.c @@ -204,7 +204,7 @@ struct process_file_node }; static error_t -process_file_get_contents (void *hook, void **contents, size_t *contents_len) +process_file_get_contents (void *hook, char **contents, size_t *contents_len) { struct process_file_node *file = hook; error_t err; diff --git a/procfs.c b/procfs.c index 5396ecf7..a5f52b50 100644 --- a/procfs.c +++ b/procfs.c @@ -12,7 +12,7 @@ struct netnode void *hook; /* (cached) contents of the node */ - void *contents; + char *contents; size_t contents_len; /* parent directory, if applicable */ @@ -20,13 +20,13 @@ struct netnode }; void -procfs_cleanup_contents_with_free (void *hook, void *cont, size_t len) +procfs_cleanup_contents_with_free (void *hook, char *cont, size_t len) { free (cont); } void -procfs_cleanup_contents_with_vm_deallocate (void *hook, void *cont, size_t len) +procfs_cleanup_contents_with_vm_deallocate (void *hook, char *cont, size_t len) { vm_deallocate (mach_task_self (), (vm_address_t) cont, (vm_size_t) len); } @@ -109,7 +109,7 @@ procfs_make_ino (struct node *np, const char *filename) return (unsigned long) jrand48 (x); } -error_t procfs_get_contents (struct node *np, void **data, size_t *data_len) +error_t procfs_get_contents (struct node *np, char **data, size_t *data_len) { if (np->nn->ops->enable_refresh_hack_and_break_readdir && np->nn->contents) { @@ -121,7 +121,7 @@ error_t procfs_get_contents (struct node *np, void **data, size_t *data_len) if (! np->nn->contents && np->nn->ops->get_contents) { - void *contents; + char *contents; size_t contents_len; error_t err; diff --git a/procfs.h b/procfs.h index 4ab3b567..8336ee85 100644 --- a/procfs.h +++ b/procfs.h @@ -17,8 +17,8 @@ struct procfs_node_ops netnode->nn_stat. For regular files and symlinks, they are what you would expect; for directories, they are an argz vector of the names of the entries. */ - error_t (*get_contents) (void *hook, void **contents, size_t *contents_len); - void (*cleanup_contents) (void *hook, void *contents, size_t contents_len); + error_t (*get_contents) (void *hook, char **contents, size_t *contents_len); + void (*cleanup_contents) (void *hook, char *contents, size_t contents_len); /* Lookup NAME in this directory, and store the result in *np. The returned node should be created by lookup() using procfs_make_node() @@ -41,8 +41,8 @@ struct procfs_node_ops }; /* These helper functions can be used as procfs_node_ops.cleanup_contents. */ -void procfs_cleanup_contents_with_free (void *, void *, size_t); -void procfs_cleanup_contents_with_vm_deallocate (void *, void *, size_t); +void procfs_cleanup_contents_with_free (void *, char *, size_t); +void procfs_cleanup_contents_with_vm_deallocate (void *, char *, size_t); /* Create a new node and return it. Returns NULL if it fails to allocate enough memory. In this case, ops->cleanup will be invoked. */ @@ -69,7 +69,7 @@ void procfs_node_chtype (struct node *np, mode_t type); corresponding child nodes. */ ino64_t procfs_make_ino (struct node *np, const char *filename); -error_t procfs_get_contents (struct node *np, void **data, size_t *data_len); +error_t procfs_get_contents (struct node *np, char **data, size_t *data_len); error_t procfs_lookup (struct node *np, const char *name, struct node **npp); void procfs_cleanup (struct node *np); diff --git a/procfs_dir.c b/procfs_dir.c index 431fea3e..4df46695 100644 --- a/procfs_dir.c +++ b/procfs_dir.c @@ -11,7 +11,7 @@ struct procfs_dir_node }; static error_t -procfs_dir_get_contents (void *hook, void **contents, size_t *contents_len) +procfs_dir_get_contents (void *hook, char **contents, size_t *contents_len) { static const char dot_dotdot[] = ".\0.."; struct procfs_dir_node *dn = hook; diff --git a/proclist.c b/proclist.c index 35422a81..b5acb26c 100644 --- a/proclist.c +++ b/proclist.c @@ -10,7 +10,7 @@ #define PID_STR_SIZE (3 * sizeof (pid_t) + 1) static error_t -proclist_get_contents (void *hook, void **contents, size_t *contents_len) +proclist_get_contents (void *hook, char **contents, size_t *contents_len) { struct ps_context *pc = hook; pidarray_t pids; diff --git a/rootdir.c b/rootdir.c index 8062f0d3..cd8949bf 100644 --- a/rootdir.c +++ b/rootdir.c @@ -44,7 +44,7 @@ get_boottime (struct ps_context *pc, struct timeval *tv) } static error_t -rootdir_gc_version (void *hook, void **contents, size_t *contents_len) +rootdir_gc_version (void *hook, char **contents, size_t *contents_len) { struct utsname uts; int r; @@ -53,7 +53,7 @@ rootdir_gc_version (void *hook, void **contents, size_t *contents_len) if (r < 0) return errno; - *contents_len = asprintf ((char **) contents, + *contents_len = asprintf (contents, "Linux version 2.6.1 (%s %s %s %s)\n", uts.sysname, uts.release, uts.version, uts.machine); @@ -63,7 +63,7 @@ rootdir_gc_version (void *hook, void **contents, size_t *contents_len) /* Uptime -- we use the start time of init to deduce it. This is probably a bit fragile, as any clock update will make the result inaccurate. */ static error_t -rootdir_gc_uptime (void *hook, void **contents, size_t *contents_len) +rootdir_gc_uptime (void *hook, char **contents, size_t *contents_len) { struct timeval time, boottime; double up_secs; @@ -85,13 +85,13 @@ rootdir_gc_uptime (void *hook, void **contents, size_t *contents_len) proc(5) specifies that it should be equal to USER_HZ times the idle value in ticks from /proc/stat. So we assume a completely idle system both here and there to make that work. */ - *contents_len = asprintf ((char **) contents, "%.2lf %.2lf\n", up_secs, up_secs); + *contents_len = asprintf (contents, "%.2lf %.2lf\n", up_secs, up_secs); return *contents_len >= 0 ? 0 : ENOMEM; } static error_t -rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) +rootdir_gc_stat (void *hook, char **contents, size_t *contents_len) { struct timeval boottime, time; struct vm_statistics vmstats; @@ -113,7 +113,7 @@ rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) timersub (&time, &boottime, &time); up_ticks = opt_clk_tck * (time.tv_sec + time.tv_usec / 1000000.); - *contents_len = asprintf ((char **) contents, + *contents_len = asprintf (contents, /* Does Mach keeps track of any of this? */ "cpu 0 0 0 %lu 0 0 0 0 0\n" "cpu0 0 0 0 %lu 0 0 0 0 0\n" @@ -130,7 +130,7 @@ rootdir_gc_stat (void *hook, void **contents, size_t *contents_len) } static error_t -rootdir_gc_loadavg (void *hook, void **contents, size_t *contents_len) +rootdir_gc_loadavg (void *hook, char **contents, size_t *contents_len) { host_load_info_data_t hli; mach_msg_type_number_t cnt; @@ -142,7 +142,7 @@ rootdir_gc_loadavg (void *hook, void **contents, size_t *contents_len) return err; assert (cnt == HOST_LOAD_INFO_COUNT); - *contents_len = asprintf ((char **) contents, + *contents_len = asprintf (contents, "%.2f %.2f %.2f 1/0 0\n", hli.avenrun[0] / (double) LOAD_SCALE, hli.avenrun[1] / (double) LOAD_SCALE, @@ -152,7 +152,7 @@ rootdir_gc_loadavg (void *hook, void **contents, size_t *contents_len) } static error_t -rootdir_gc_meminfo (void *hook, void **contents, size_t *contents_len) +rootdir_gc_meminfo (void *hook, char **contents, size_t *contents_len) { host_basic_info_data_t hbi; mach_msg_type_number_t cnt; @@ -169,7 +169,7 @@ rootdir_gc_meminfo (void *hook, void **contents, size_t *contents_len) return err; assert (cnt == HOST_BASIC_INFO_COUNT); - *contents_len = asprintf ((char **) contents, + *contents_len = asprintf (contents, "MemTotal: %14lu kB\n" "MemFree: %14lu kB\n" "Active: %14lu kB\n" @@ -187,7 +187,7 @@ rootdir_gc_meminfo (void *hook, void **contents, size_t *contents_len) } static error_t -rootdir_gc_vmstat (void *hook, void **contents, size_t *contents_len) +rootdir_gc_vmstat (void *hook, char **contents, size_t *contents_len) { host_basic_info_data_t hbi; mach_msg_type_number_t cnt; @@ -204,7 +204,7 @@ rootdir_gc_vmstat (void *hook, void **contents, size_t *contents_len) return err; assert (cnt == HOST_BASIC_INFO_COUNT); - *contents_len = asprintf ((char **) contents, + *contents_len = asprintf (contents, "nr_free_pages %lu\n" "nr_inactive_anon %lu\n" "nr_active_anon %lu\n" @@ -232,7 +232,7 @@ rootdir_gc_vmstat (void *hook, void **contents, size_t *contents_len) } static error_t -rootdir_gc_cmdline (void *hook, void **contents, size_t *contents_len) +rootdir_gc_cmdline (void *hook, char **contents, size_t *contents_len) { struct ps_context *pc = hook; struct proc_stat *ps; @@ -259,7 +259,7 @@ rootdir_gc_cmdline (void *hook, void **contents, size_t *contents_len) memcpy (*contents, proc_stat_args (ps), *contents_len); argz_stringify (*contents, *contents_len, ' '); - ((char *) *contents)[*contents_len - 1] = '\n'; + (*contents)[*contents_len - 1] = '\n'; out: _proc_stat_free (ps); @@ -267,9 +267,9 @@ out: } static error_t -rootdir_gc_fakeself (void *hook, void **contents, size_t *contents_len) +rootdir_gc_fakeself (void *hook, char **contents, size_t *contents_len) { - *contents_len = asprintf ((char **) contents, "%d", opt_fake_self); + *contents_len = asprintf (contents, "%d", opt_fake_self); return *contents_len >= 0 ? 0 : ENOMEM; } -- cgit v1.2.3 From 6e202c432e2f16dfa83a7dc21b759c03623fa394 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 11:33:22 +0000 Subject: Detect asprintf's ENOMEM in procfs.c rather than everywhere * procfs.h: Make CONTENTS_LEN an ssize_t rather than a size_t, and document the change. * procfs.c (procfs_get_contents): Initialize CONTENTS_LEN to a negative value, and fail with ENOMEM if it's still negative after the callback returns. (everywhere): Update to ssize_t. * dircat.c, netfs.c, process.c, procfs_dir.c, proclist.c, rootdir.c: Update to ssize_t and the new GET_CONTENTS semantics. --- dircat.c | 4 ++-- netfs.c | 8 ++++---- process.c | 54 ++++++++++++++++++++---------------------------------- procfs.c | 13 ++++++++----- procfs.h | 14 ++++++++------ procfs_dir.c | 2 +- proclist.c | 2 +- rootdir.c | 30 +++++++++++++++--------------- 8 files changed, 59 insertions(+), 68 deletions(-) (limited to 'rootdir.c') diff --git a/dircat.c b/dircat.c index 93bb2fed..bb66508a 100644 --- a/dircat.c +++ b/dircat.c @@ -8,7 +8,7 @@ struct dircat_node }; static error_t -dircat_get_contents (void *hook, char **contents, size_t *contents_len) +dircat_get_contents (void *hook, char **contents, ssize_t *contents_len) { struct dircat_node *dcn = hook; int i, sz, pos; @@ -20,7 +20,7 @@ dircat_get_contents (void *hook, char **contents, size_t *contents_len) for (i=0; dcn->dirs[i]; i++) { char *subcon; - size_t sublen; + ssize_t sublen; err = procfs_get_contents (dcn->dirs[i], &subcon, &sublen); if (err) diff --git a/netfs.c b/netfs.c index 6fd82a00..e41e0623 100644 --- a/netfs.c +++ b/netfs.c @@ -30,7 +30,7 @@ int netfs_maxsymlinks = PROCFS_MAXSYMLINKS; error_t netfs_validate_stat (struct node *np, struct iouser *cred) { char *contents; - size_t contents_len; + ssize_t contents_len; error_t err; /* Only symlinks need to have their size filled, before a read is @@ -54,7 +54,7 @@ error_t netfs_attempt_read (struct iouser *cred, struct node *np, loff_t offset, size_t *len, void *data) { char *contents; - size_t contents_len; + ssize_t contents_len; error_t err; err = procfs_get_contents (np, &contents, &contents_len); @@ -79,7 +79,7 @@ error_t netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf) { char *contents; - size_t contents_len; + ssize_t contents_len; error_t err; err = procfs_get_contents (np, &contents, &contents_len); @@ -137,7 +137,7 @@ error_t netfs_get_dirents (struct iouser *cred, struct node *dir, vm_size_t bufsize, int *amt) { char *contents; - size_t contents_len; + ssize_t contents_len; error_t err; err = procfs_get_contents (dir, &contents, &contents_len); diff --git a/process.c b/process.c index fa795522..624f79e7 100644 --- a/process.c +++ b/process.c @@ -12,18 +12,18 @@ /* Implementations for the process_file_desc.get_contents callback. */ -static char * -process_file_gc_cmdline (struct proc_stat *ps, size_t *len) +static ssize_t +process_file_gc_cmdline (struct proc_stat *ps, char **contents) { - *len = proc_stat_args_len(ps); - return proc_stat_args(ps); + *contents = proc_stat_args(ps); + return proc_stat_args_len(ps); } -static char * -process_file_gc_environ (struct proc_stat *ps, size_t *len) +static ssize_t +process_file_gc_environ (struct proc_stat *ps, char **contents) { - *len = proc_stat_args_len(ps); - return proc_stat_args(ps); + *contents = proc_stat_env(ps); + return proc_stat_env_len(ps); } static char state_char (struct proc_stat *ps) @@ -71,17 +71,16 @@ static long long int jiff_tv (time_value_t tv) return usecs * 100 / 1000000; } -static char * -process_file_gc_stat (struct proc_stat *ps, size_t *len) +static ssize_t +process_file_gc_stat (struct proc_stat *ps, char **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, + return asprintf (contents, "%d (%s) %c " /* pid, command, state */ "%d %d %d " /* ppid, pgid, session */ "%d %d " /* controling tty stuff */ @@ -122,31 +121,23 @@ process_file_gc_stat (struct proc_stat *ps, size_t *len) 0, 0, 0, 0LL); - - return len >= 0 ? contents : NULL; } -static char * -process_file_gc_statm (struct proc_stat *ps, size_t *len) +static ssize_t +process_file_gc_statm (struct proc_stat *ps, char **contents) { task_basic_info_t tbi = proc_stat_task_basic_info (ps); - char *contents; - - *len = asprintf (&contents, + return asprintf (contents, "%lu %lu 0 0 0 0 0\n", tbi->virtual_size / sysconf(_SC_PAGE_SIZE), tbi->resident_size / sysconf(_SC_PAGE_SIZE)); - - return len >= 0 ? contents : NULL; } -static char * -process_file_gc_status (struct proc_stat *ps, size_t *len) +static ssize_t +process_file_gc_status (struct proc_stat *ps, char **contents) { task_basic_info_t tbi = proc_stat_task_basic_info (ps); - char *contents; - - *len = asprintf (&contents, + return asprintf (contents, "Name:\t%s\n" "State:\t%s\n" "Tgid:\t%u\n" @@ -172,8 +163,6 @@ process_file_gc_status (struct proc_stat *ps, size_t *len) tbi->resident_size / 1024, tbi->resident_size / 1024, proc_stat_num_threads (ps)); - - return len >= 0 ? contents : NULL; } @@ -186,7 +175,7 @@ struct process_file_desc /* 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); + ssize_t (*get_contents) (struct proc_stat *ps, char **contents); /* The cmdline and environ contents don't need any cleaning since they are part of a proc_stat structure. */ @@ -204,7 +193,7 @@ struct process_file_node }; static error_t -process_file_get_contents (void *hook, char **contents, size_t *contents_len) +process_file_get_contents (void *hook, char **contents, ssize_t *contents_len) { struct process_file_node *file = hook; error_t err; @@ -215,10 +204,7 @@ process_file_get_contents (void *hook, char **contents, size_t *contents_len) 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 = file->desc->get_contents (file->ps, contents); return 0; } diff --git a/procfs.c b/procfs.c index a5f52b50..6d15e4fd 100644 --- a/procfs.c +++ b/procfs.c @@ -13,20 +13,20 @@ struct netnode /* (cached) contents of the node */ char *contents; - size_t contents_len; + ssize_t contents_len; /* parent directory, if applicable */ struct node *parent; }; void -procfs_cleanup_contents_with_free (void *hook, char *cont, size_t len) +procfs_cleanup_contents_with_free (void *hook, char *cont, ssize_t len) { free (cont); } void -procfs_cleanup_contents_with_vm_deallocate (void *hook, char *cont, size_t len) +procfs_cleanup_contents_with_vm_deallocate (void *hook, char *cont, ssize_t len) { vm_deallocate (mach_task_self (), (vm_address_t) cont, (vm_size_t) len); } @@ -109,7 +109,7 @@ procfs_make_ino (struct node *np, const char *filename) return (unsigned long) jrand48 (x); } -error_t procfs_get_contents (struct node *np, char **data, size_t *data_len) +error_t procfs_get_contents (struct node *np, char **data, ssize_t *data_len) { if (np->nn->ops->enable_refresh_hack_and_break_readdir && np->nn->contents) { @@ -122,12 +122,15 @@ error_t procfs_get_contents (struct node *np, char **data, size_t *data_len) if (! np->nn->contents && np->nn->ops->get_contents) { char *contents; - size_t contents_len; + ssize_t contents_len; error_t err; + contents_len = -1; err = np->nn->ops->get_contents (np->nn->hook, &contents, &contents_len); if (err) return err; + if (contents_len < 0) + return ENOMEM; np->nn->contents = contents; np->nn->contents_len = contents_len; diff --git a/procfs.h b/procfs.h index 8336ee85..e8ef18b3 100644 --- a/procfs.h +++ b/procfs.h @@ -16,9 +16,11 @@ struct procfs_node_ops symlink or directory, as determined by the file mode in netnode->nn_stat. For regular files and symlinks, they are what you would expect; for directories, they are an argz vector of the - names of the entries. */ - error_t (*get_contents) (void *hook, char **contents, size_t *contents_len); - void (*cleanup_contents) (void *hook, char *contents, size_t contents_len); + names of the entries. If upon return, *CONTENTS_LEN is negative or + unchanged, the call is considered to have failed because of a memory + allocation error. */ + error_t (*get_contents) (void *hook, char **contents, ssize_t *contents_len); + void (*cleanup_contents) (void *hook, char *contents, ssize_t contents_len); /* Lookup NAME in this directory, and store the result in *np. The returned node should be created by lookup() using procfs_make_node() @@ -41,8 +43,8 @@ struct procfs_node_ops }; /* These helper functions can be used as procfs_node_ops.cleanup_contents. */ -void procfs_cleanup_contents_with_free (void *, char *, size_t); -void procfs_cleanup_contents_with_vm_deallocate (void *, char *, size_t); +void procfs_cleanup_contents_with_free (void *, char *, ssize_t); +void procfs_cleanup_contents_with_vm_deallocate (void *, char *, ssize_t); /* Create a new node and return it. Returns NULL if it fails to allocate enough memory. In this case, ops->cleanup will be invoked. */ @@ -69,7 +71,7 @@ void procfs_node_chtype (struct node *np, mode_t type); corresponding child nodes. */ ino64_t procfs_make_ino (struct node *np, const char *filename); -error_t procfs_get_contents (struct node *np, char **data, size_t *data_len); +error_t procfs_get_contents (struct node *np, char **data, ssize_t *data_len); error_t procfs_lookup (struct node *np, const char *name, struct node **npp); void procfs_cleanup (struct node *np); diff --git a/procfs_dir.c b/procfs_dir.c index 4df46695..8ec3f7a5 100644 --- a/procfs_dir.c +++ b/procfs_dir.c @@ -11,7 +11,7 @@ struct procfs_dir_node }; static error_t -procfs_dir_get_contents (void *hook, char **contents, size_t *contents_len) +procfs_dir_get_contents (void *hook, char **contents, ssize_t *contents_len) { static const char dot_dotdot[] = ".\0.."; struct procfs_dir_node *dn = hook; diff --git a/proclist.c b/proclist.c index b5acb26c..38368feb 100644 --- a/proclist.c +++ b/proclist.c @@ -10,7 +10,7 @@ #define PID_STR_SIZE (3 * sizeof (pid_t) + 1) static error_t -proclist_get_contents (void *hook, char **contents, size_t *contents_len) +proclist_get_contents (void *hook, char **contents, ssize_t *contents_len) { struct ps_context *pc = hook; pidarray_t pids; diff --git a/rootdir.c b/rootdir.c index cd8949bf..364b0731 100644 --- a/rootdir.c +++ b/rootdir.c @@ -44,7 +44,7 @@ get_boottime (struct ps_context *pc, struct timeval *tv) } static error_t -rootdir_gc_version (void *hook, char **contents, size_t *contents_len) +rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len) { struct utsname uts; int r; @@ -57,13 +57,13 @@ rootdir_gc_version (void *hook, char **contents, size_t *contents_len) "Linux version 2.6.1 (%s %s %s %s)\n", uts.sysname, uts.release, uts.version, uts.machine); - return *contents_len >= 0 ? 0 : ENOMEM; + return 0; } /* Uptime -- we use the start time of init to deduce it. This is probably a bit fragile, as any clock update will make the result inaccurate. */ static error_t -rootdir_gc_uptime (void *hook, char **contents, size_t *contents_len) +rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len) { struct timeval time, boottime; double up_secs; @@ -87,11 +87,11 @@ rootdir_gc_uptime (void *hook, char **contents, size_t *contents_len) and there to make that work. */ *contents_len = asprintf (contents, "%.2lf %.2lf\n", up_secs, up_secs); - return *contents_len >= 0 ? 0 : ENOMEM; + return 0; } static error_t -rootdir_gc_stat (void *hook, char **contents, size_t *contents_len) +rootdir_gc_stat (void *hook, char **contents, ssize_t *contents_len) { struct timeval boottime, time; struct vm_statistics vmstats; @@ -126,11 +126,11 @@ rootdir_gc_stat (void *hook, char **contents, size_t *contents_len) vmstats.pageins, vmstats.pageouts, boottime.tv_sec); - return *contents_len >= 0 ? 0 : ENOMEM; + return 0; } static error_t -rootdir_gc_loadavg (void *hook, char **contents, size_t *contents_len) +rootdir_gc_loadavg (void *hook, char **contents, ssize_t *contents_len) { host_load_info_data_t hli; mach_msg_type_number_t cnt; @@ -148,11 +148,11 @@ rootdir_gc_loadavg (void *hook, char **contents, size_t *contents_len) hli.avenrun[1] / (double) LOAD_SCALE, hli.avenrun[2] / (double) LOAD_SCALE); - return *contents_len >= 0 ? 0 : ENOMEM; + return 0; } static error_t -rootdir_gc_meminfo (void *hook, char **contents, size_t *contents_len) +rootdir_gc_meminfo (void *hook, char **contents, ssize_t *contents_len) { host_basic_info_data_t hbi; mach_msg_type_number_t cnt; @@ -183,11 +183,11 @@ rootdir_gc_meminfo (void *hook, char **contents, size_t *contents_len) (long unsigned) vmstats.inactive_count * PAGE_SIZE / 1024, (long unsigned) vmstats.wire_count * PAGE_SIZE / 1024); - return *contents_len >= 0 ? 0 : ENOMEM; + return 0; } static error_t -rootdir_gc_vmstat (void *hook, char **contents, size_t *contents_len) +rootdir_gc_vmstat (void *hook, char **contents, ssize_t *contents_len) { host_basic_info_data_t hbi; mach_msg_type_number_t cnt; @@ -228,11 +228,11 @@ rootdir_gc_vmstat (void *hook, char **contents, size_t *contents_len) (long unsigned) vmstats.pageouts, (long unsigned) vmstats.faults); - return *contents_len >= 0 ? 0 : ENOMEM; + return 0; } static error_t -rootdir_gc_cmdline (void *hook, char **contents, size_t *contents_len) +rootdir_gc_cmdline (void *hook, char **contents, ssize_t *contents_len) { struct ps_context *pc = hook; struct proc_stat *ps; @@ -267,10 +267,10 @@ out: } static error_t -rootdir_gc_fakeself (void *hook, char **contents, size_t *contents_len) +rootdir_gc_fakeself (void *hook, char **contents, ssize_t *contents_len) { *contents_len = asprintf (contents, "%d", opt_fake_self); - return *contents_len >= 0 ? 0 : ENOMEM; + return 0; } -- cgit v1.2.3 From f522af65aa004fea09705c74115836c6acd1cddb Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 14:15:54 +0000 Subject: Revamp procfs_dir * procfs_dir.c, procfs_dir.h: Revamp the interface to make the more complicated use cases somewhat less hackish. * process.c: Update, specify a default make_node function. * rootdir.c: Likewise; make this optional "self" link use case somewhat less hackish. --- process.c | 16 +++++++------ procfs_dir.c | 78 ++++++++++++++++++++++++++++++++++++++---------------------- procfs_dir.h | 48 +++++++++++++++++++++++++++---------- rootdir.c | 36 +++++++++++++++------------- 4 files changed, 113 insertions(+), 65 deletions(-) (limited to 'rootdir.c') diff --git a/process.c b/process.c index 624f79e7..61688f7e 100644 --- a/process.c +++ b/process.c @@ -209,7 +209,7 @@ process_file_get_contents (void *hook, char **contents, ssize_t *contents_len) } static struct node * -process_file_make_node (void *dir_hook, void *entry_hook) +process_file_make_node (void *dir_hook, const void *entry_hook) { static const struct procfs_node_ops ops = { .get_contents = process_file_get_contents, @@ -245,7 +245,6 @@ process_file_make_node (void *dir_hook, void *entry_hook) 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, @@ -254,7 +253,6 @@ static struct procfs_dir_entry entries[] = { }, { .name = "environ", - .make_node = process_file_make_node, .hook = & (struct process_file_desc) { .get_contents = process_file_gc_environ, .needs = PSTAT_ENV, @@ -265,7 +263,6 @@ static struct procfs_dir_entry entries[] = { { /* Beware of the hack below, which requires this to be entries[2]. */ .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 @@ -276,7 +273,6 @@ static struct procfs_dir_entry entries[] = { }, { .name = "statm", - .make_node = process_file_make_node, .hook = & (struct process_file_desc) { .get_contents = process_file_gc_statm, .needs = PSTAT_TASK_BASIC, @@ -285,7 +281,6 @@ static struct procfs_dir_entry entries[] = { }, { .name = "status", - .make_node = process_file_make_node, .hook = & (struct process_file_desc) { .get_contents = process_file_gc_status, .needs = PSTAT_PID | PSTAT_ARGS | PSTAT_STATE | PSTAT_PROC_INFO @@ -299,6 +294,13 @@ static struct procfs_dir_entry entries[] = { error_t process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np) { + static const struct procfs_dir_ops dir_ops = { + .entries = entries, + .cleanup = (void (*)(void *)) _proc_stat_free, + .entry_ops = { + .make_node = process_file_make_node, + }, + }; struct proc_stat *ps; int owner; error_t err; @@ -317,7 +319,7 @@ process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np) accessed in a more robust and straightforward way. */ ((struct process_file_desc *) entries[2].hook)->mode = opt_stat_mode; - *np = procfs_dir_make_node (entries, ps, (void (*)(void *)) _proc_stat_free); + *np = procfs_dir_make_node (&dir_ops, ps); if (! *np) return ENOMEM; diff --git a/procfs_dir.c b/procfs_dir.c index 8ec3f7a5..dfe30a26 100644 --- a/procfs_dir.c +++ b/procfs_dir.c @@ -5,49 +5,71 @@ struct procfs_dir_node { - const struct procfs_dir_entry *entries; + const struct procfs_dir_ops *ops; void *hook; - void (*cleanup) (void *hook); }; +static int +entry_exists (struct procfs_dir_node *dir, const struct procfs_dir_entry *ent) +{ + if (ent->ops.exists) + return ent->ops.exists (dir->hook, ent->hook); + if (dir->ops->entry_ops.exists) + return dir->ops->entry_ops.exists (dir->hook, ent->hook); + + return 1; +} + static error_t procfs_dir_get_contents (void *hook, char **contents, ssize_t *contents_len) { static const char dot_dotdot[] = ".\0.."; - struct procfs_dir_node *dn = hook; + struct procfs_dir_node *dir = hook; const struct procfs_dir_entry *ent; - char *pos; + int pos; - *contents_len = sizeof dot_dotdot; - for (ent = dn->entries; ent->name; ent++) - *contents_len += strlen (ent->name) + 1; + /* Evaluate how much space is needed. Note that we include the hidden + entries, just in case their status changes between now and then. */ + pos = sizeof dot_dotdot; + for (ent = dir->ops->entries; ent->name; ent++) + pos += strlen (ent->name) + 1; - *contents = malloc (*contents_len); + *contents = malloc (pos); if (! *contents) return ENOMEM; memcpy (*contents, dot_dotdot, sizeof dot_dotdot); - pos = *contents + sizeof dot_dotdot; - for (ent = dn->entries; ent->name; ent++) + pos = sizeof dot_dotdot; + for (ent = dir->ops->entries; ent->name; ent++) { - strcpy (pos, ent->name); + if (! entry_exists (dir, ent)) + continue; + + strcpy (*contents + pos, ent->name); pos += strlen (ent->name) + 1; } + *contents_len = pos; return 0; } static error_t procfs_dir_lookup (void *hook, const char *name, struct node **np) { - struct procfs_dir_node *dn = hook; + struct procfs_dir_node *dir = hook; const struct procfs_dir_entry *ent; - for (ent = dn->entries; ent->name && strcmp (name, ent->name); ent++); + for (ent = dir->ops->entries; ent->name && strcmp (name, ent->name); ent++); if (! ent->name) return ENOENT; - *np = ent->make_node (dn->hook, ent->hook); + if (ent->ops.make_node) + *np = ent->ops.make_node (dir->hook, ent->hook); + else if (dir->ops->entry_ops.make_node) + *np = dir->ops->entry_ops.make_node (dir->hook, ent->hook); + else + return EGRATUITOUS; + if (! *np) return ENOMEM; @@ -57,17 +79,16 @@ procfs_dir_lookup (void *hook, const char *name, struct node **np) static void procfs_dir_cleanup (void *hook) { - struct procfs_dir_node *dn = hook; + struct procfs_dir_node *dir = hook; - if (dn->cleanup) - dn->cleanup (dn->hook); + if (dir->ops->cleanup) + dir->ops->cleanup (dir->hook); - free (dn); + free (dir); } struct node * -procfs_dir_make_node (const struct procfs_dir_entry *entries, - void *dir_hook, void (*cleanup) (void *dir_hook)) +procfs_dir_make_node (const struct procfs_dir_ops *dir_ops, void *dir_hook) { static const struct procfs_node_ops ops = { .get_contents = procfs_dir_get_contents, @@ -75,21 +96,20 @@ procfs_dir_make_node (const struct procfs_dir_entry *entries, .cleanup_contents = procfs_cleanup_contents_with_free, .cleanup = procfs_dir_cleanup, }; - struct procfs_dir_node *dn; + struct procfs_dir_node *dir; - dn = malloc (sizeof *dn); - if (! dn) + dir = malloc (sizeof *dir); + if (! dir) { - if (cleanup) - cleanup (dir_hook); + if (dir_ops->cleanup) + dir_ops->cleanup (dir_hook); return NULL; } - dn->entries = entries; - dn->hook = dir_hook; - dn->cleanup = cleanup; + dir->ops = dir_ops; + dir->hook = dir_hook; - return procfs_make_node (&ops, dn); + return procfs_make_node (&ops, dir); } diff --git a/procfs_dir.h b/procfs_dir.h index 4eb934e0..12e99d2a 100644 --- a/procfs_dir.h +++ b/procfs_dir.h @@ -1,20 +1,44 @@ +/* This module provides an abstraction layer for implementing simple + directories with (mostly) static contents. The user defines the + contents of the directory by providing a table of entries and various + optional callback functions. */ -/* Each entry associates a name with a callback function for creating new - nodes corresponding to that entry. */ +/* These operations define how a given entry will behave. Either can be + omitted, both from the entry-specific operations and from the + directory-wide defaults. */ +struct procfs_dir_entry_ops +{ + /* Called when this entry is looked up to create a corresponding node. */ + struct node *(*make_node)(void *dir_hook, const void *entry_hook); + /* If this is provided and returns 0, this entry will be hidden. */ + int (*exists)(void *dir_hook, const void *entry_hook); +}; + +/* Describes an individual directory entry, associating a NAME with + * arbitrary HOOK data and node-specific OPS. */ struct procfs_dir_entry { const char *name; - struct node *(*make_node)(void *dir_hook, void *entry_hook); - void *hook; + const void *hook; + struct procfs_dir_entry_ops ops; +}; + +/* Describes a complete directory. ENTRIES is a table terminated by a + null NAME field. ENTRY_OPS provides default operations for the + entries which don't specify them. The optional CLEANUP function + should release all the resources associated with the directory hook. */ +struct procfs_dir_ops +{ + const struct procfs_dir_entry *entries; + void (*cleanup)(void *dir_hook); + struct procfs_dir_entry_ops entry_ops; }; -/* A simple directory is built from a table of entries. The table is - terminated by a null NAME pointer. The DIR_HOOK is passed the - MAKE_NODE callback function of looked up procfs_dir_entries, and to - the provided CLEANUP function when the directory is destroyed. - Returns the new directory node. If not enough memory can be - allocated, CLEANUP is invoked immediately and NULL is returned. */ +/* Create and return a new node for the directory described in OPS. + The DIR_HOOK is passed the MAKE_NODE callback function of looked up + entries, as well as to the CLEANUP callback when the node is + destroyed. If not enough memory can be allocated, OPS->CLEANUP is + invoked immediately and NULL is returned. */ struct node * -procfs_dir_make_node (const struct procfs_dir_entry *entries, - void *dir_hook, void (*cleanup) (void *dir_hook)); +procfs_dir_make_node (const struct procfs_dir_ops *ops, void *dir_hook); diff --git a/rootdir.c b/rootdir.c index 364b0731..dcee9a54 100644 --- a/rootdir.c +++ b/rootdir.c @@ -266,6 +266,12 @@ out: return err; } +static int +rootdir_fakeself_exists () +{ + return opt_fake_self >= 0; +} + static error_t rootdir_gc_fakeself (void *hook, char **contents, ssize_t *contents_len) { @@ -275,13 +281,13 @@ rootdir_gc_fakeself (void *hook, char **contents, ssize_t *contents_len) static struct node * -rootdir_file_make_node (void *dir_hook, void *entry_hook) +rootdir_file_make_node (void *dir_hook, const void *entry_hook) { return procfs_make_node (entry_hook, dir_hook); } static struct node * -rootdir_symlink_make_node (void *dir_hook, void *entry_hook) +rootdir_symlink_make_node (void *dir_hook, const void *entry_hook) { struct node *np = procfs_make_node (entry_hook, dir_hook); if (np) @@ -292,15 +298,17 @@ rootdir_symlink_make_node (void *dir_hook, void *entry_hook) static const struct procfs_dir_entry rootdir_entries[] = { { .name = "self", - .make_node = rootdir_symlink_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_fakeself, .cleanup_contents = procfs_cleanup_contents_with_free, }, + .ops = { + .make_node = rootdir_symlink_make_node, + .exists = rootdir_fakeself_exists, + } }, { .name = "version", - .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_version, .cleanup_contents = procfs_cleanup_contents_with_free, @@ -308,7 +316,6 @@ static const struct procfs_dir_entry rootdir_entries[] = { }, { .name = "uptime", - .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_uptime, .cleanup_contents = procfs_cleanup_contents_with_free, @@ -316,7 +323,6 @@ static const struct procfs_dir_entry rootdir_entries[] = { }, { .name = "stat", - .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_stat, .cleanup_contents = procfs_cleanup_contents_with_free, @@ -324,7 +330,6 @@ static const struct procfs_dir_entry rootdir_entries[] = { }, { .name = "loadavg", - .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_loadavg, .cleanup_contents = procfs_cleanup_contents_with_free, @@ -332,7 +337,6 @@ static const struct procfs_dir_entry rootdir_entries[] = { }, { .name = "meminfo", - .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_meminfo, .cleanup_contents = procfs_cleanup_contents_with_free, @@ -340,7 +344,6 @@ static const struct procfs_dir_entry rootdir_entries[] = { }, { .name = "vmstat", - .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_vmstat, .cleanup_contents = procfs_cleanup_contents_with_free, @@ -348,7 +351,6 @@ static const struct procfs_dir_entry rootdir_entries[] = { }, { .name = "cmdline", - .make_node = rootdir_file_make_node, .hook = & (struct procfs_node_ops) { .get_contents = rootdir_gc_cmdline, .cleanup_contents = procfs_cleanup_contents_with_free, @@ -360,12 +362,12 @@ static const struct procfs_dir_entry rootdir_entries[] = { struct node *rootdir_make_node (struct ps_context *pc) { - const struct procfs_dir_entry *entries; - - entries = rootdir_entries; - if (opt_fake_self < 0) - entries++; - - return procfs_dir_make_node (entries, pc, NULL); + static const struct procfs_dir_ops ops = { + .entries = rootdir_entries, + .entry_ops = { + .make_node = rootdir_file_make_node, + }, + }; + return procfs_dir_make_node (&ops, pc); } -- cgit v1.2.3 From 434f79cbfa00c7370724dc25091b5a42bdf8d9e1 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 19:04:48 +0000 Subject: Fix the global idle time * rootdir.c: Replace INIT_PID by KERNEL_PID, for boot time and idle time purposes. (get_idletime): New function, queries the kernel's idle thread. (rootdir_gc_uptime, rootdir_gc_stat): Use the new function and provide the real idle time. --- rootdir.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 13 deletions(-) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index dcee9a54..728008e5 100644 --- a/rootdir.c +++ b/rootdir.c @@ -16,15 +16,16 @@ using them would require locking and as a consequence it would be more complicated, not simpler. */ -#define INIT_PID 1 +#define KERNEL_PID 2 +/* We get the boot time by using that of the kernel process. */ static error_t get_boottime (struct ps_context *pc, struct timeval *tv) { struct proc_stat *ps; error_t err; - err = _proc_stat_create (INIT_PID, pc, &ps); + err = _proc_stat_create (KERNEL_PID, pc, &ps); if (err) return err; @@ -43,6 +44,63 @@ get_boottime (struct ps_context *pc, struct timeval *tv) return err; } +/* We get the idle time by querying the kernel's idle thread. */ +static error_t +get_idletime (struct ps_context *pc, struct timeval *tv) +{ + struct proc_stat *ps, *pst; + thread_basic_info_t tbi; + error_t err; + int i; + + err = _proc_stat_create (KERNEL_PID, pc, &ps); + if (err) + return err; + + pst = NULL, tbi = NULL; + + err = proc_stat_set_flags (ps, PSTAT_NUM_THREADS); + if (err || !(proc_stat_flags (ps) & PSTAT_NUM_THREADS)) + { + err = EIO; + goto out; + } + + /* Look for the idle thread */ + for (i=0; !tbi || !(tbi->flags & TH_FLAGS_IDLE); i++) + { + if (pst) + _proc_stat_free (pst); + + pst = NULL, tbi = NULL; + if (i >= proc_stat_num_threads (ps)) + { + err = ESRCH; + goto out; + } + + err = proc_stat_thread_create (ps, i, &pst); + if (err) + continue; + + err = proc_stat_set_flags (pst, PSTAT_THREAD_BASIC); + if (err || ! (proc_stat_flags (pst) & PSTAT_THREAD_BASIC)) + continue; + + tbi = proc_stat_thread_basic_info (pst); + } + + /* We found it! */ + tv->tv_sec = tbi->system_time.seconds; + tv->tv_usec = tbi->system_time.microseconds; + err = 0; + +out: + if (pst) _proc_stat_free (pst); + _proc_stat_free (ps); + return err; +} + static error_t rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len) { @@ -65,8 +123,8 @@ rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len) static error_t rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len) { - struct timeval time, boottime; - double up_secs; + struct timeval time, boottime, idletime; + double up_secs, idle_secs; error_t err; err = gettimeofday (&time, NULL); @@ -77,15 +135,20 @@ rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len) if (err) return err; + err = get_idletime (hook, &idletime); + if (err) + return err; + timersub (&time, &boottime, &time); up_secs = time.tv_sec + time.tv_usec / 1000000.; + idle_secs = idletime.tv_sec + idletime.tv_usec / 1000000.; /* The second field is the total idle time. As far as I know we don't keep track of it. However, procps uses it to compute "USER_HZ", and proc(5) specifies that it should be equal to USER_HZ times the idle value in ticks from /proc/stat. So we assume a completely idle system both here and there to make that work. */ - *contents_len = asprintf (contents, "%.2lf %.2lf\n", up_secs, up_secs); + *contents_len = asprintf (contents, "%.2lf %.2lf\n", up_secs, idle_secs); return 0; } @@ -93,9 +156,9 @@ rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len) static error_t rootdir_gc_stat (void *hook, char **contents, ssize_t *contents_len) { - struct timeval boottime, time; + struct timeval boottime, time, idletime; struct vm_statistics vmstats; - unsigned long up_ticks; + unsigned long up_ticks, idle_ticks; error_t err; err = gettimeofday (&time, NULL); @@ -106,23 +169,26 @@ rootdir_gc_stat (void *hook, char **contents, ssize_t *contents_len) if (err) return err; + err = get_idletime (hook, &idletime); + if (err) + return err; + err = vm_statistics (mach_task_self (), &vmstats); if (err) return EIO; timersub (&time, &boottime, &time); up_ticks = opt_clk_tck * (time.tv_sec + time.tv_usec / 1000000.); + idle_ticks = opt_clk_tck * (idletime.tv_sec + idletime.tv_usec / 1000000.); *contents_len = asprintf (contents, - /* Does Mach keeps track of any of this? */ - "cpu 0 0 0 %lu 0 0 0 0 0\n" - "cpu0 0 0 0 %lu 0 0 0 0 0\n" + "cpu %lu 0 0 %lu 0 0 0 0 0\n" + "cpu0 %lu 0 0 %lu 0 0 0 0 0\n" "intr 0\n" - /* This we know. */ "page %d %d\n" "btime %lu\n", - up_ticks, - up_ticks, + up_ticks - idle_ticks, idle_ticks, + up_ticks - idle_ticks, idle_ticks, vmstats.pageins, vmstats.pageouts, boottime.tv_sec); -- cgit v1.2.3 From 7b027a34676880bded1a05a5c47bfa85a6e79092 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Mon, 23 Aug 2010 20:21:52 +0000 Subject: Make sure the clock never runs backwards. * process.c, rootdir.c: When converting timeval structures into seconds or jiffies, make sure that floating point rounding errors don't make the clock the result jump backwards on second boundaries. --- process.c | 4 ++-- rootdir.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'rootdir.c') diff --git a/process.c b/process.c index 1f9d5781..68e7bc1d 100644 --- a/process.c +++ b/process.c @@ -58,8 +58,8 @@ static const char *state_string (struct proc_stat *ps) static long long int timeval_jiffies (time_value_t tv) { - double secs = tv.seconds + tv.microseconds / 1000000.; - return secs * opt_clk_tck; + double secs = tv.seconds * 1000000. + tv.microseconds; + return secs * opt_clk_tck / 1000000.; } /* Actual content generators */ diff --git a/rootdir.c b/rootdir.c index 728008e5..c6ddd87c 100644 --- a/rootdir.c +++ b/rootdir.c @@ -140,8 +140,8 @@ rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len) return err; timersub (&time, &boottime, &time); - up_secs = time.tv_sec + time.tv_usec / 1000000.; - idle_secs = idletime.tv_sec + idletime.tv_usec / 1000000.; + up_secs = (time.tv_sec * 1000000. + time.tv_usec) / 1000000.; + idle_secs = (idletime.tv_sec * 1000000. + idletime.tv_usec) / 1000000.; /* The second field is the total idle time. As far as I know we don't keep track of it. However, procps uses it to compute "USER_HZ", and @@ -178,8 +178,8 @@ rootdir_gc_stat (void *hook, char **contents, ssize_t *contents_len) return EIO; timersub (&time, &boottime, &time); - up_ticks = opt_clk_tck * (time.tv_sec + time.tv_usec / 1000000.); - idle_ticks = opt_clk_tck * (idletime.tv_sec + idletime.tv_usec / 1000000.); + up_ticks = opt_clk_tck * (time.tv_sec * 1000000. + time.tv_usec) / 1000000.; + idle_ticks = opt_clk_tck * (idletime.tv_sec * 1000000. + idletime.tv_usec) / 1000000.; *contents_len = asprintf (contents, "cpu %lu 0 0 %lu 0 0 0 0 0\n" -- cgit v1.2.3 From e1c831a43ac1945db5a52ee6873856b9399dca76 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Wed, 25 Aug 2010 05:47:08 +0000 Subject: Add a PROFILE mode * Makefile: Change FOOFLAGS defaults to appropriate values when $(PROFILE) is defined. * rootdir.c: Add an "exit" file, which causes exit to be called when looked up, so that profiling data can be written to disk. --- Makefile | 10 +++++++++- rootdir.c | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'rootdir.c') diff --git a/Makefile b/Makefile index b8c055f6..a397522f 100644 --- a/Makefile +++ b/Makefile @@ -6,13 +6,21 @@ LIBS = -lnetfs -lps CC = gcc CFLAGS = -Wall -g CPPFLAGS = +LDFLAGS = + +ifdef PROFILE +CFLAGS= -g -pg +CPPFLAGS= -DPROFILE +LDFLAGS= -static +LIBS= -lnetfs -lfshelp -liohelp -lps -lports -lthreads -lihash -lshouldbeinlibc +endif CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 all: $(TARGET) $(TARGET): $(OBJS) - $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) clean: $(RM) $(TARGET) $(OBJS) diff --git a/rootdir.c b/rootdir.c index c6ddd87c..204bc02b 100644 --- a/rootdir.c +++ b/rootdir.c @@ -422,6 +422,15 @@ static const struct procfs_dir_entry rootdir_entries[] = { .cleanup_contents = procfs_cleanup_contents_with_free, }, }, +#ifdef PROFILE + /* In order to get a usable gmon.out file, we must apparently use exit(). */ + { + .name = "exit", + .ops = { + .make_node = exit, + }, + }, +#endif {} }; -- cgit v1.2.3 From 164db73bb35173f45a7eaba1984c3169cba778e8 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Wed, 25 Aug 2010 12:03:16 +0000 Subject: Add swap information to the top-level stat file * rootdir.c (rootdir_gc_meminfo): Add swap information. * TODO: Update. --- TODO | 1 - rootdir.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'rootdir.c') diff --git a/TODO b/TODO index b4a39b05..241c61ae 100644 --- a/TODO +++ b/TODO @@ -1,2 +1 @@ -* Add swap information * Threads in /proc/[pid]/task/[n] diff --git a/rootdir.c b/rootdir.c index 204bc02b..419f774e 100644 --- a/rootdir.c +++ b/rootdir.c @@ -1,7 +1,10 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -101,6 +104,22 @@ out: return err; } +static error_t +get_swapinfo (default_pager_info_t *info) +{ + mach_port_t defpager; + error_t err; + + defpager = file_name_lookup (_SERVERS_DEFPAGER, O_READ, 0); + if (defpager == MACH_PORT_NULL) + return errno; + + err = default_pager_info (defpager, info); + mach_port_deallocate (mach_task_self (), defpager); + + return err; +} + static error_t rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len) { @@ -223,6 +242,7 @@ rootdir_gc_meminfo (void *hook, char **contents, ssize_t *contents_len) host_basic_info_data_t hbi; mach_msg_type_number_t cnt; struct vm_statistics vmstats; + default_pager_info_t swap; error_t err; err = vm_statistics (mach_task_self (), &vmstats); @@ -234,6 +254,10 @@ rootdir_gc_meminfo (void *hook, char **contents, ssize_t *contents_len) if (err) return err; + err = get_swapinfo (&swap); + if (err) + return err; + assert (cnt == HOST_BASIC_INFO_COUNT); *contents_len = asprintf (contents, "MemTotal: %14lu kB\n" @@ -241,13 +265,17 @@ rootdir_gc_meminfo (void *hook, char **contents, ssize_t *contents_len) "Active: %14lu kB\n" "Inactive: %14lu kB\n" "Mlocked: %14lu kB\n" + "SwapTotal:%14lu kB\n" + "SwapFree: %14lu kB\n" , /* TODO: check that these are really 1024-bytes kBs. */ (long unsigned) hbi.memory_size / 1024, (long unsigned) vmstats.free_count * PAGE_SIZE / 1024, (long unsigned) vmstats.active_count * PAGE_SIZE / 1024, (long unsigned) vmstats.inactive_count * PAGE_SIZE / 1024, - (long unsigned) vmstats.wire_count * PAGE_SIZE / 1024); + (long unsigned) vmstats.wire_count * PAGE_SIZE / 1024, + (long unsigned) swap.dpi_total_space / 1024, + (long unsigned) swap.dpi_free_space / 1024); return 0; } -- cgit v1.2.3 From 0f3c9c2640ffd76f1d60f16dce6d16c47aac98b4 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Wed, 25 Aug 2010 19:04:24 +0000 Subject: Add some comments in rootdir.c * rootdir.c: Add page breaks to separate sections and add header comments for them. --- rootdir.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index 419f774e..2a2ab5a5 100644 --- a/rootdir.c +++ b/rootdir.c @@ -21,6 +21,9 @@ #define KERNEL_PID 2 + +/* Helper functions */ + /* We get the boot time by using that of the kernel process. */ static error_t get_boottime (struct ps_context *pc, struct timeval *tv) @@ -120,6 +123,9 @@ get_swapinfo (default_pager_info_t *info) return err; } + +/* Content generators */ + static error_t rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len) { @@ -137,8 +143,6 @@ rootdir_gc_version (void *hook, char **contents, ssize_t *contents_len) return 0; } -/* Uptime -- we use the start time of init to deduce it. This is probably a bit - fragile, as any clock update will make the result inaccurate. */ static error_t rootdir_gc_uptime (void *hook, char **contents, ssize_t *contents_len) { @@ -373,10 +377,16 @@ rootdir_gc_fakeself (void *hook, char **contents, ssize_t *contents_len) return 0; } + +/* Glue logic and entries table */ static struct node * rootdir_file_make_node (void *dir_hook, const void *entry_hook) { + /* The entry hook we use is actually a procfs_node_ops for the file to be + created. The hook associated to these newly created files (and passed + to the generators above as a consequence) is always the same global + ps_context, which we get from rootdir_make_node as the directory hook. */ return procfs_make_node (entry_hook, dir_hook); } -- cgit v1.2.3 From 5c7310fd853620627b57c72ddcc3b212f29f6056 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Thu, 26 Aug 2010 23:03:40 +0000 Subject: Add copyright notices * dircat.c, dircat.h, main.c, main.h, netfs.c, process.c, process.h, procfs.c, procfs.h, procfs_dir.c, procfs_dir.h, proclist.c, proclist.h, rootdir.c, rootdir.h: Add copyright notices. --- dircat.c | 19 +++++++++++++++++++ dircat.h | 19 +++++++++++++++++++ main.c | 19 +++++++++++++++++++ main.h | 19 +++++++++++++++++++ netfs.c | 19 +++++++++++++++++++ process.c | 19 +++++++++++++++++++ process.h | 19 +++++++++++++++++++ procfs.c | 19 +++++++++++++++++++ procfs.h | 19 +++++++++++++++++++ procfs_dir.c | 19 +++++++++++++++++++ procfs_dir.h | 19 +++++++++++++++++++ proclist.c | 19 +++++++++++++++++++ proclist.h | 19 +++++++++++++++++++ rootdir.c | 19 +++++++++++++++++++ rootdir.h | 19 +++++++++++++++++++ 15 files changed, 285 insertions(+) (limited to 'rootdir.c') diff --git a/dircat.c b/dircat.c index d24e8345..5a60899a 100644 --- a/dircat.c +++ b/dircat.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, concatenation of two directories. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include "procfs.h" diff --git a/dircat.h b/dircat.h index 951d2021..4177b384 100644 --- a/dircat.h +++ b/dircat.h @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, concatenation of two directories. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + /* Append the contents of NUM_DIRS directories. DIRS is an array of directory nodes. One reference is consumed for each of them. If a memory allocation error occurs, or if one of the directories is a diff --git a/main.c b/main.c index eaab9867..94fc227d 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, main program. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include diff --git a/main.h b/main.h index 28d1b023..4e28b7eb 100644 --- a/main.h +++ b/main.h @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, command-line options set by main.c. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + /* Startup options */ extern int opt_clk_tck; extern mode_t opt_stat_mode; diff --git a/netfs.c b/netfs.c index 02a4bf54..24a6603f 100644 --- a/netfs.c +++ b/netfs.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, interface with libnetfs. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include diff --git a/process.c b/process.c index 47e34708..6652a4e9 100644 --- a/process.c +++ b/process.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, implementation of process directories. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include diff --git a/process.h b/process.h index 8c2ee636..b230a281 100644 --- a/process.h +++ b/process.h @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, implementation of process directories. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include /* Create a node for a directory representing the given PID, as published by diff --git a/procfs.c b/procfs.c index f7b28347..ee52de7a 100644 --- a/procfs.c +++ b/procfs.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, basic infrastructure. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include diff --git a/procfs.h b/procfs.h index a9665f97..64782ec4 100644 --- a/procfs.h +++ b/procfs.h @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, basic infrastructure. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include diff --git a/procfs_dir.c b/procfs_dir.c index dfe30a26..c250aa48 100644 --- a/procfs_dir.c +++ b/procfs_dir.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, infrastructure for directories. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include "procfs.h" diff --git a/procfs_dir.h b/procfs_dir.h index 12e99d2a..94c5b019 100644 --- a/procfs_dir.h +++ b/procfs_dir.h @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, infrastructure for directories. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + /* This module provides an abstraction layer for implementing simple directories with (mostly) static contents. The user defines the contents of the directory by providing a table of entries and various diff --git a/proclist.c b/proclist.c index fe5d0cff..58b942dc 100644 --- a/proclist.c +++ b/proclist.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, list of processes as a directory. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include diff --git a/proclist.h b/proclist.h index ce69dde3..bfe95b3d 100644 --- a/proclist.h +++ b/proclist.h @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, list of processes as a directory. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include struct node * diff --git a/rootdir.c b/rootdir.c index 2a2ab5a5..da068cf4 100644 --- a/rootdir.c +++ b/rootdir.c @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, permanent files of the root directory. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include #include #include diff --git a/rootdir.h b/rootdir.h index 0caee258..6980da8f 100644 --- a/rootdir.h +++ b/rootdir.h @@ -1,3 +1,22 @@ +/* Hurd /proc filesystem, permanent files of the root directory. + Copyright (C) 2010 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include struct node * -- cgit v1.2.3 From 8dc9884fc74243a6810fdcac603e1941962b666a Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Wed, 1 Sep 2010 10:19:49 +0000 Subject: Use the user-provided kernel PID for uptime * rootdir.c (get_boottime, get_idletime): replace KERNEL_PID with the opt_kernel_pid command-line option. * main.c (argp): Document the change. --- main.c | 3 ++- rootdir.c | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'rootdir.c') diff --git a/main.c b/main.c index 94fc227d..3a976ccc 100644 --- a/main.c +++ b/main.c @@ -114,7 +114,8 @@ struct argp argp = { "purposes. If PID is omitted, \"self\" will point to init. " "(default: no self link)" }, { "kernel-process", 'k', "PID", 0, - "Process identifier for the kernel, used to retreive its command line " + "Process identifier for the kernel, used to retreive its command " + "line, as well as the global up and idle times. " "(default: 2)" }, { "compatible", 'c', NULL, 0, "Try to be compatible with the Linux procps utilities. " diff --git a/rootdir.c b/rootdir.c index da068cf4..15ef8bce 100644 --- a/rootdir.c +++ b/rootdir.c @@ -38,8 +38,6 @@ using them would require locking and as a consequence it would be more complicated, not simpler. */ -#define KERNEL_PID 2 - /* Helper functions */ @@ -50,7 +48,7 @@ get_boottime (struct ps_context *pc, struct timeval *tv) struct proc_stat *ps; error_t err; - err = _proc_stat_create (KERNEL_PID, pc, &ps); + err = _proc_stat_create (opt_kernel_pid, pc, &ps); if (err) return err; @@ -78,7 +76,7 @@ get_idletime (struct ps_context *pc, struct timeval *tv) error_t err; int i; - err = _proc_stat_create (KERNEL_PID, pc, &ps); + err = _proc_stat_create (opt_kernel_pid, pc, &ps); if (err) return err; -- cgit v1.2.3 From f4dfd14bb77fd884a0e5afe306c677e7e873f41d Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Tue, 22 Feb 2011 21:06:36 +0100 Subject: Add Buffers and Cached to /proc/meminfo * rootdir.c (rootdir_gc_meminfo): Add Buffers and Cached, set to 0. --- rootdir.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'rootdir.c') diff --git a/rootdir.c b/rootdir.c index 15ef8bce..1fa71b03 100644 --- a/rootdir.c +++ b/rootdir.c @@ -283,15 +283,18 @@ rootdir_gc_meminfo (void *hook, char **contents, ssize_t *contents_len) *contents_len = asprintf (contents, "MemTotal: %14lu kB\n" "MemFree: %14lu kB\n" + "Buffers: %14lu kB\n" + "Cached: %14lu kB\n" "Active: %14lu kB\n" "Inactive: %14lu kB\n" "Mlocked: %14lu kB\n" "SwapTotal:%14lu kB\n" "SwapFree: %14lu kB\n" , - /* TODO: check that these are really 1024-bytes kBs. */ (long unsigned) hbi.memory_size / 1024, (long unsigned) vmstats.free_count * PAGE_SIZE / 1024, + 0, + 0, (long unsigned) vmstats.active_count * PAGE_SIZE / 1024, (long unsigned) vmstats.inactive_count * PAGE_SIZE / 1024, (long unsigned) vmstats.wire_count * PAGE_SIZE / 1024, -- cgit v1.2.3 From d9fc76bd4e8c9a459fad7152135b738496318415 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Tue, 27 Dec 2011 17:31:20 +0100 Subject: Do not use msgport information * process.c (process_lookup_pid): Set PSTAT_NO_MSGPORT flag. * rootdir.c (get_boottime, get_idletime, rootdir_gc_cmdline): Set PSTAT_NO_MSGPORT flag. --- process.c | 2 ++ rootdir.c | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'rootdir.c') diff --git a/process.c b/process.c index 6652a4e9..e812a1f1 100644 --- a/process.c +++ b/process.c @@ -362,6 +362,8 @@ process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np) if (err) return EIO; + proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); + err = proc_stat_set_flags (ps, PSTAT_OWNER_UID); if (err || ! (proc_stat_flags (ps) & PSTAT_OWNER_UID)) { diff --git a/rootdir.c b/rootdir.c index 1fa71b03..018de617 100644 --- a/rootdir.c +++ b/rootdir.c @@ -52,6 +52,8 @@ get_boottime (struct ps_context *pc, struct timeval *tv) if (err) return err; + proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); + err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC); if (err || !(proc_stat_flags (ps) & PSTAT_TASK_BASIC)) err = EIO; @@ -82,6 +84,8 @@ get_idletime (struct ps_context *pc, struct timeval *tv) pst = NULL, tbi = NULL; + proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); + err = proc_stat_set_flags (ps, PSTAT_NUM_THREADS); if (err || !(proc_stat_flags (ps) & PSTAT_NUM_THREADS)) { @@ -360,6 +364,8 @@ rootdir_gc_cmdline (void *hook, char **contents, ssize_t *contents_len) if (err) return EIO; + proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); + err = proc_stat_set_flags (ps, PSTAT_ARGS); if (err || ! (proc_stat_flags (ps) & PSTAT_ARGS)) { -- cgit v1.2.3 From f8471a5a6b20693d3c7afc0645de62c842b82bd3 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Tue, 27 Dec 2011 18:13:00 +0100 Subject: Revert "Do not use msgport information" This reverts commit d9fc76bd4e8c9a459fad7152135b738496318415, as it breaks /proc/pid/stat --- process.c | 2 -- rootdir.c | 6 ------ 2 files changed, 8 deletions(-) (limited to 'rootdir.c') diff --git a/process.c b/process.c index e812a1f1..6652a4e9 100644 --- a/process.c +++ b/process.c @@ -362,8 +362,6 @@ process_lookup_pid (struct ps_context *pc, pid_t pid, struct node **np) if (err) return EIO; - proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); - err = proc_stat_set_flags (ps, PSTAT_OWNER_UID); if (err || ! (proc_stat_flags (ps) & PSTAT_OWNER_UID)) { diff --git a/rootdir.c b/rootdir.c index 018de617..1fa71b03 100644 --- a/rootdir.c +++ b/rootdir.c @@ -52,8 +52,6 @@ get_boottime (struct ps_context *pc, struct timeval *tv) if (err) return err; - proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); - err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC); if (err || !(proc_stat_flags (ps) & PSTAT_TASK_BASIC)) err = EIO; @@ -84,8 +82,6 @@ get_idletime (struct ps_context *pc, struct timeval *tv) pst = NULL, tbi = NULL; - proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); - err = proc_stat_set_flags (ps, PSTAT_NUM_THREADS); if (err || !(proc_stat_flags (ps) & PSTAT_NUM_THREADS)) { @@ -364,8 +360,6 @@ rootdir_gc_cmdline (void *hook, char **contents, ssize_t *contents_len) if (err) return EIO; - proc_stat_set_flags (ps, PSTAT_NO_MSGPORT); - err = proc_stat_set_flags (ps, PSTAT_ARGS); if (err || ! (proc_stat_flags (ps) & PSTAT_ARGS)) { -- cgit v1.2.3