summaryrefslogtreecommitdiff
path: root/procfs/procfs_nonpid_files.c
diff options
context:
space:
mode:
Diffstat (limited to 'procfs/procfs_nonpid_files.c')
-rw-r--r--procfs/procfs_nonpid_files.c514
1 files changed, 514 insertions, 0 deletions
diff --git a/procfs/procfs_nonpid_files.c b/procfs/procfs_nonpid_files.c
new file mode 100644
index 00000000..2c1209ee
--- /dev/null
+++ b/procfs/procfs_nonpid_files.c
@@ -0,0 +1,514 @@
+/* procfs -- a translator for providing GNU/Linux compatible
+ proc pseudo-filesystem
+
+ procfs_nonpid_files.c -- This file contains function definitions
+ to create and update the non-Per PID
+ files and their contents.
+
+ Copyright (C) 2008, FSF.
+ Written as a Summer of Code Project
+
+
+ procfs 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.
+
+ procfs 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+
+ A portion of the code in this file is based on vmstat.c code
+ present in the hurd repositories copyrighted to FSF. The
+ Copyright notice from that file is given below.
+
+ Copyright (C) 1997,98,2002 Free Software Foundation, Inc.
+ Written by Miles Bader <miles@gnu.org>
+ This file is part of the GNU Hurd.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <hurd/netfs.h>
+#include <hurd/ihash.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/sysinfo.h>
+#include <mach/vm_statistics.h>
+#include <mach/default_pager.h>
+#include <hurd.h>
+#include <hurd/paths.h>
+#include <mach.h>
+#include <ps.h>
+#include <time.h>
+
+#include "procfs.h"
+
+typedef long long val_t;
+#define BADVAL ((val_t) - 1LL)
+
+/* default pager port (must be privileged to fetch this). */
+mach_port_t def_pager;
+struct default_pager_info def_pager_info;
+
+error_t procfs_create_uptime (struct procfs_dir *dir,
+ struct node **node,
+ time_t timestamp)
+{
+ int err;
+ char *file_name, *file_path;
+ struct procfs_dir_entry *dir_entry;
+
+ if (asprintf (&file_name, "%s", "uptime") == -1)
+ return errno;
+ if (asprintf (&file_path, "%s", "uptime") == -1)
+ return errno;
+
+ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL);
+ err = procfs_create_node (dir_entry, file_path, node);
+
+ free (file_name);
+ free (file_path);
+
+ return err;
+}
+
+error_t procfs_create_version(struct procfs_dir *dir,
+ struct node **node,
+ time_t timestamp)
+{
+ int err;
+ char *file_name, *file_path;
+ struct procfs_dir_entry *dir_entry;
+
+ if (asprintf (&file_name, "%s", "version") == -1)
+ return errno;
+ if (asprintf (&file_path, "%s", "version") == -1)
+ return errno;
+
+ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL);
+ err = procfs_create_node (dir_entry, file_path, node);
+
+ free (file_name);
+ free (file_path);
+
+ return 0;
+}
+
+error_t procfs_create_stat (struct procfs_dir *dir,
+ struct node **node,
+ time_t timestamp)
+{
+ int err;
+ char *file_name, *file_path;
+ struct procfs_dir_entry *dir_entry;
+
+ if (asprintf (&file_name, "%s", "stat") == -1)
+ return errno;
+ if (asprintf (&file_path, "%s", "stat") == -1)
+ return errno;
+
+ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL);
+ err = procfs_create_node (dir_entry, file_path, node);
+
+ free (file_name);
+ free (file_path);
+
+ return err;
+}
+
+error_t procfs_create_meminfo (struct procfs_dir *dir,
+ struct node **node,
+ time_t timestamp)
+{
+ int err;
+ char *file_name, *file_path;
+ struct procfs_dir_entry *dir_entry;
+
+ if (asprintf (&file_name, "%s", "meminfo") == -1)
+ return errno;
+ if (asprintf (&file_path, "%s", "meminfo") == -1)
+ return errno;
+
+ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL);
+ err = procfs_create_node (dir_entry, file_path, node);
+
+ free (file_name);
+ free (file_path);
+
+ return err;
+}
+
+error_t procfs_create_loadavg (struct procfs_dir *dir,
+ struct node **node,
+ time_t timestamp)
+{
+ int err;
+ char *file_name, *file_path;
+ struct procfs_dir_entry *dir_entry;
+
+ if (asprintf (&file_name, "%s", "loadavg") == -1)
+ return errno;
+ if (asprintf (&file_path, "%s", "loadavg") == -1)
+ return errno;
+
+ dir_entry = update_pid_entries (dir, file_name, timestamp, NULL);
+ err = procfs_create_node (dir_entry, file_path, node);
+
+ free (file_name);
+ free (file_path);
+
+ return err;
+}
+
+error_t get_uptime (struct timeval *uptime)
+{
+ struct timeval boot_time, now;
+ error_t err;
+ struct proc_stat *ps;
+
+ err = _proc_stat_create (1, ps_context, &ps);
+
+ if (err)
+ return err;
+
+ err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC);
+ if (!err && !(ps->flags & PSTAT_TASK_BASIC))
+ err = EGRATUITOUS;
+
+ if (! err)
+ {
+ time_value_t *const tv = &proc_stat_task_basic_info (ps)->creation_time;
+ boot_time.tv_sec = tv->seconds;
+ boot_time.tv_usec = tv->microseconds;
+ if (gettimeofday (&now, 0) < 0)
+ error (0, errno, "gettimeofday");
+ timersub (&now, &boot_time, uptime);
+ }
+
+ _proc_stat_free (ps);
+ return err;
+}
+
+error_t get_total_times (struct timeval *total_user_time,
+ struct timeval *total_system_time)
+{
+ error_t err;
+ pid_t *pids;
+ int pidslen = 0, count;
+ struct proc_stat *ps;
+ struct task_thread_times_info live_threads_times;
+
+ struct timeval total_user_time_tmp;
+ struct timeval total_system_time_tmp;
+ struct timeval tmpval;
+
+ timerclear (&total_user_time_tmp);
+ timerclear (&total_system_time_tmp);
+
+ pids = NULL;
+ err = proc_getallpids (getproc (), &pids, &pidslen);
+
+ if (!err)
+ for (count = 0; count < pidslen; count++)
+ {
+ err = _proc_stat_create (pids[count], ps_context, &ps);
+ if (err)
+ return err;
+
+ err = proc_stat_set_flags (ps, PSTAT_TASK_BASIC);
+ if (!err && !(ps->flags & PSTAT_TASK_BASIC))
+ err = EGRATUITOUS;
+
+ if (! err)
+ {
+ tmpval.tv_sec = proc_stat_task_basic_info (ps)->user_time.seconds;
+ tmpval.tv_usec = proc_stat_task_basic_info (ps)->user_time.seconds;
+ timeradd (&total_user_time_tmp, &tmpval, &total_user_time_tmp);
+
+ tmpval.tv_sec = proc_stat_task_basic_info (ps)->system_time.seconds;
+ tmpval.tv_usec = proc_stat_task_basic_info (ps)->system_time.seconds;
+ timeradd (&total_system_time_tmp, &tmpval, &total_system_time_tmp);
+
+ error_t err = set_field_value (ps, PSTAT_TASK);
+ if (! err)
+ {
+ err = get_task_thread_times (ps->task, &live_threads_times);
+ if (! err)
+ {
+ tmpval.tv_sec = live_threads_times.user_time.seconds;
+ tmpval.tv_usec = live_threads_times.user_time.microseconds;
+ timeradd (&total_user_time_tmp, &tmpval, &total_user_time_tmp);
+
+ tmpval.tv_sec = live_threads_times.system_time.seconds;
+ tmpval.tv_usec = live_threads_times.system_time.microseconds;
+ timeradd (&total_system_time_tmp, &tmpval, &total_system_time_tmp);
+ }
+ }
+ }
+ _proc_stat_free (ps);
+ }
+
+ total_user_time->tv_sec = total_user_time_tmp.tv_sec;
+ total_user_time->tv_usec = total_user_time_tmp.tv_usec;
+
+ total_system_time->tv_sec = total_system_time_tmp.tv_sec;
+ total_system_time->tv_usec = total_system_time_tmp.tv_usec;
+
+ return err;
+}
+
+error_t procfs_read_nonpid_stat (struct dir_entry *dir_entry,
+ off_t offset, size_t *len, void *data)
+{
+ char *stat_data;
+ error_t err;
+ jiffy_t total_user_time_jiffy, total_system_time_jiffy;
+ jiffy_t idle_time_jiffy;
+ struct timeval uptime, total_user_time, total_system_time;
+ struct timeval idle_time;
+
+ err = get_uptime (&uptime);
+
+ if (! err)
+ {
+ err = get_total_times (&total_user_time, &total_system_time);
+
+ if (! err)
+ {
+ timersub (&uptime, &total_system_time,
+ &idle_time);
+
+ total_user_time_jiffy = 100 * ((double) total_user_time.tv_sec +
+ (double) total_user_time.tv_usec / (1000 * 1000));
+ total_system_time_jiffy = 100 * ((double) total_system_time.tv_sec +
+ (double) total_system_time.tv_usec / (1000 * 1000));
+ idle_time_jiffy = 100 * ((double) idle_time.tv_sec +
+ (double) idle_time.tv_usec / (1000 * 1000));
+
+ if (asprintf (&stat_data, "cpu %llu %llu %llu %llu %llu %llu %d %d %d\n"
+ "cpu0 %llu %llu %llu %llu %llu %llu %d %d %d\n"
+ "intr %llu %llu %llu %llu %llu %llu %d %d %d\n",
+ total_user_time_jiffy, (long long unsigned) 0,
+ total_system_time_jiffy, idle_time_jiffy,
+ (long long unsigned) 0, (long long unsigned) 0,
+ 0, 0, 0,
+ total_user_time_jiffy, (long long unsigned) 0,
+ total_system_time_jiffy, idle_time_jiffy,
+ (long long unsigned) 0, (long long unsigned) 0,
+ 0, 0, 0,
+ (long long unsigned) 0,
+ (long long unsigned) 0, (long long unsigned) 0, (long long unsigned) 0,
+ (long long unsigned) 0,
+ (long long unsigned) 0, (long long unsigned) 0,
+ (long long unsigned) 0, (long long unsigned) 0) == -1)
+ return errno;
+ }
+ }
+
+ memcpy (data, stat_data, strlen(stat_data));
+ *len = strlen (data);
+
+ free (stat_data);
+ return err;
+}
+
+/* Makes sure the default pager port and associated
+ info exists, and returns 0 if not (after printing
+ an error). */
+static int
+ensure_def_pager_info ()
+{
+ error_t err;
+
+ if (def_pager == MACH_PORT_NULL)
+ {
+ mach_port_t host;
+
+ err = get_privileged_ports (&host, 0);
+ if (err == EPERM)
+ {
+ /* We are not root, so try opening the /servers file. */
+ def_pager = file_name_lookup (_SERVERS_DEFPAGER, O_READ, 0);
+ if (def_pager == MACH_PORT_NULL)
+ {
+ error (0, errno, _SERVERS_DEFPAGER);
+ return 0;
+ }
+ }
+ if (def_pager == MACH_PORT_NULL)
+ {
+ if (err)
+ {
+ error (0, err, "get_privileged_ports");
+ return 0;
+ }
+
+ err = vm_set_default_memory_manager (host, &def_pager);
+ mach_port_deallocate (mach_task_self (), host);
+
+ if (err)
+ {
+ error (0, err, "vm_set_default_memory_manager");
+ return 0;
+ }
+ }
+ }
+
+ if (!MACH_PORT_VALID (def_pager))
+ {
+ if (def_pager == MACH_PORT_NULL)
+ {
+ error (0, 0,
+ "No default pager running, so no swap information available");
+ def_pager = MACH_PORT_DEAD; /* so we don't try again */
+ }
+ return 0;
+ }
+
+ err = default_pager_info (def_pager, &def_pager_info);
+ if (err)
+ error (0, err, "default_pager_info");
+ return (err == 0);
+}
+
+#define SWAP_FIELD(getter, expr) \
+ static val_t getter () \
+ { return ensure_def_pager_info () ? (val_t) (expr) : BADVAL; }
+
+SWAP_FIELD (get_swap_size, def_pager_info.dpi_total_space)
+SWAP_FIELD (get_swap_free, def_pager_info.dpi_free_space)
+SWAP_FIELD (get_swap_page_size, def_pager_info.dpi_page_size)
+SWAP_FIELD (get_swap_active, (def_pager_info.dpi_total_space
+ - def_pager_info.dpi_free_space))
+
+error_t procfs_read_nonpid_meminfo (struct dir_entry *dir_entry,
+ off_t offset, size_t *len, void *data)
+{
+ char *meminfo_data;
+ error_t err;
+ struct vm_statistics vmstats;
+
+ err = vm_statistics (mach_task_self (), &vmstats);
+
+ unsigned long mem_size = ((vmstats.free_count +
+ vmstats.active_count + vmstats.inactive_count +
+ vmstats.wire_count) * vmstats.pagesize) / 1024;
+
+ if (! err)
+ if (asprintf (&meminfo_data, "MemTotal:\t%lu kB\n"
+ "MemFree:\t%lu kB\n"
+ "Buffers:\t%ld kB\n"
+ "Cached:\t\t%ld kB\n"
+ "SwapCached:\t%ld kB\n"
+ "Active:\t\t%lu kB\n"
+ "Inactive:\t%lu kB\n"
+ "HighTotal:\t%lu kB\n"
+ "HighFree:\t%lu kB\n"
+ "LowTotal:\t%lu kB\n"
+ "LowFree:\t%lu kB\n"
+ "SwapTotal:\t%llu kB\n"
+ "SwapFree:\t%llu kB\n",
+ mem_size, (PAGES_TO_BYTES(vmstats.free_count)) / 1024 , 0, 0, 0,
+ (PAGES_TO_BYTES(vmstats.active_count)) / 1024,
+ (PAGES_TO_BYTES(vmstats.inactive_count)) / 1024, 0, 0, 0, 0,
+ get_swap_size () / 1024, get_swap_free () / 1024) == -1)
+ return errno;
+
+ memcpy (data, meminfo_data, strlen(meminfo_data));
+ *len = strlen (data);
+
+ free (meminfo_data);
+ return err;
+}
+
+error_t procfs_read_nonpid_loadavg (struct dir_entry *dir_entry,
+ off_t offset, size_t *len, void *data)
+{
+ char *loadavg_data;
+ error_t err;
+ processor_set_info_t info;
+ natural_t *count;
+ struct host_load_info *load;
+ mach_port_t host;
+
+ err = ps_host_load_info (&load);
+ if (err)
+ error (0, err, "ps_host_load_info");
+
+ if (! err)
+ if (asprintf (&loadavg_data, "%.2f %.2f %.2f %d/%d %d\n",
+ (double)load->avenrun[0] / (double)LOAD_SCALE,
+ (double)load->avenrun[1] / (double)LOAD_SCALE,
+ (double)load->avenrun[2] / (double)LOAD_SCALE, 0, 0, 0) == -1)
+ return errno;
+
+ memcpy (data, loadavg_data, strlen(loadavg_data));
+ *len = strlen (data);
+
+ free (loadavg_data);
+ return err;
+}
+
+error_t procfs_read_nonpid_uptime (struct dir_entry *dir_entry,
+ off_t offset, size_t *len, void *data)
+{
+ char *uptime_data;
+ error_t err;
+ double uptime_secs, idle_time_secs;
+
+ struct timeval uptime_val;
+ struct timeval uptime, total_user_time, total_system_time;
+ struct timeval idle_time;
+
+
+ err = get_uptime (&uptime);
+ if (! err)
+ {
+ err = get_total_times (&total_user_time,
+ &total_system_time);
+ if (! err)
+ {
+ timersub (&uptime, &total_system_time,
+ &idle_time);
+
+ uptime_secs = (double) uptime.tv_sec +
+ (double) uptime.tv_usec / (1000 * 1000);
+
+ idle_time_secs = (double) idle_time.tv_sec +
+ (double) idle_time.tv_usec / (1000 * 1000);
+
+ if (asprintf (&uptime_data, "%.2f %.2f\n",
+ uptime_secs, idle_time_secs) == -1)
+ return errno;
+ }
+ }
+
+
+ memcpy (data, uptime_data, strlen(uptime_data));
+ *len = strlen (data);
+
+ free (uptime_data);
+ return err;
+}
+
+error_t procfs_read_nonpid_version (struct dir_entry *dir_entry,
+ off_t offset, size_t *len, void *data)
+{
+ char *version_data;
+ error_t err = 0;
+
+ if (asprintf (&version_data, "Linux version 2.6.18\n", NULL) == -1)
+ return errno;
+
+ memcpy (data, version_data, strlen(version_data));
+ *len = strlen (data);
+
+ free (version_data);
+ return err;
+}