/* 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 This file is part of the GNU Hurd. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 (double *uptime_secs) { struct timeval boot_time, uptime, 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); *uptime_secs = (double)uptime.tv_sec + ((double)uptime.tv_usec / 1000000); } _proc_stat_free (ps); return err; } error_t get_total_times (double *total_user_time_secs , double *total_system_time_secs ) { error_t err; pid_t *pids; int pidslen = 0, count; struct proc_stat *ps; struct task_thread_times_info live_threads_times; *total_user_time_secs = 0; *total_system_time_secs = 0; 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) { *total_user_time_secs += ((double) (proc_stat_task_basic_info (ps)->user_time.seconds)) + (((double) (proc_stat_task_basic_info (ps)->user_time.microseconds)) / (1000 * 1000)); *total_system_time_secs += ((double) (proc_stat_task_basic_info (ps)->system_time.seconds)) + (((double) (proc_stat_task_basic_info (ps)->system_time.microseconds)) / (1000 * 1000)); error_t err = set_field_value (ps, PSTAT_TASK); if (! err) { err = get_task_thread_times (ps->task, &live_threads_times); if (! err) { *total_user_time_secs += ((double) (live_threads_times.user_time.seconds)) + (((double) (live_threads_times.user_time.microseconds)) / (1000 * 1000)); *total_system_time_secs += ((double) (live_threads_times.system_time.seconds)) + (((double) (live_threads_times.system_time.microseconds)) / (1000 * 1000)); } } } _proc_stat_free (ps); } return err; } error_t procfs_write_nonpid_stat (struct dir_entry *dir_entry, off_t offset, size_t *len, void *data) { char *stat_data; error_t err; double uptime_secs, total_user_time_secs; double total_system_time_secs, idle_time_secs; err = get_uptime (&uptime_secs); if (! err) { err = get_total_times (&total_user_time_secs, &total_system_time_secs); if (! err) { idle_time_secs = uptime_secs - total_system_time_secs; /* If the values are multiplied by 100, it iss done so to adjust values in seconds to jiffies. */ if (asprintf (&stat_data, "cpu %ld %ld %ld %ld %ld %ld %d %d %d\n" "cpu0 %ld %ld %ld %ld %ld %ld %d %d %d\n" "intr %ld %ld %ld %ld %ld %ld %d %d %d\n", (long)(total_user_time_secs * 100), 0, (long)(total_system_time_secs * 100), (long) (idle_time_secs * 100), 0, 0, 0, 0, 0, (long)(total_user_time_secs * 100), 0, (long)(total_system_time_secs * 100), (long)(idle_time_secs * 100), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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_write_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%lu kB\n" "SwapFree:\t%lu 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 (), get_swap_free ()) == -1) return errno; memcpy (data, meminfo_data, strlen(meminfo_data)); *len = strlen (data); free (meminfo_data); return err; } error_t procfs_write_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_write_nonpid_uptime (struct dir_entry *dir_entry, off_t offset, size_t *len, void *data) { char *uptime_data; error_t err; double uptime_secs, total_user_time_secs; double total_system_time_secs, idle_time_secs; err = get_uptime (&uptime_secs); if (! err) { err = get_total_times (&total_user_time_secs, &total_system_time_secs); if (! err) { idle_time_secs = uptime_secs - total_system_time_secs; 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; }