2008-02-01 21:36:15 +03:00
|
|
|
/* GKrellM
|
2010-09-15 19:32:14 +04:00
|
|
|
| Copyright (C) 1999-2010 Bill Wilson
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
|
| Author: Bill Wilson billw@gkrellm.net
|
|
|
|
| Latest versions might be found at: http://gkrellm.net
|
|
|
|
|
|
|
|
|
| darwin.c code is Copyright (c) Ben Hines <bhines@alumni.ucsd.edu>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| GKrellM 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 3 of the License, or
|
|
|
|
| (at your option) any later version.
|
|
|
|
|
|
|
|
|
| GKrellM 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, see http://www.gnu.org/licenses/
|
2008-10-04 12:55:47 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
| Additional permission under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
|
| If you modify this program, or any covered work, by linking or
|
|
|
|
| combining it with the OpenSSL project's OpenSSL library (or a
|
|
|
|
| modified version of that library), containing parts covered by
|
|
|
|
| the terms of the OpenSSL or SSLeay licenses, you are granted
|
|
|
|
| additional permission to convey the resulting work.
|
|
|
|
| Corresponding Source for a non-source form of such a combination
|
|
|
|
| shall include the source code for the parts of OpenSSL used as well
|
|
|
|
| as that of the covered work.
|
2008-02-01 21:36:15 +03:00
|
|
|
*/
|
|
|
|
|
2008-09-28 22:06:24 +04:00
|
|
|
#ifdef HAVE_KVM_H
|
2008-02-01 21:36:15 +03:00
|
|
|
#include <kvm.h>
|
2008-09-28 22:06:24 +04:00
|
|
|
#endif
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
#include <mach/mach_init.h>
|
|
|
|
#include <mach/mach_host.h>
|
|
|
|
#include <mach/vm_map.h>
|
|
|
|
|
2008-09-28 22:06:24 +04:00
|
|
|
#ifdef HAVE_KVM_H
|
2008-02-01 21:36:15 +03:00
|
|
|
kvm_t *kvmd = NULL;
|
|
|
|
char errbuf[_POSIX2_LINE_MAX];
|
2008-09-28 22:06:24 +04:00
|
|
|
#endif
|
2008-02-01 21:36:15 +03:00
|
|
|
|
2010-09-23 19:31:24 +04:00
|
|
|
static void gkrellm_sys_disk_cleanup(void);
|
|
|
|
|
|
|
|
|
2008-02-01 21:36:15 +03:00
|
|
|
void
|
|
|
|
gkrellm_sys_main_init(void)
|
|
|
|
{
|
2008-09-28 22:06:24 +04:00
|
|
|
#ifdef HAVE_KVM_H
|
2008-02-01 21:36:15 +03:00
|
|
|
/* We just ignore error, here. Even if GKrellM doesn't have
|
|
|
|
| kmem privilege, it runs with available information.
|
|
|
|
*/
|
|
|
|
kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
|
|
|
|
if (setgid(getgid()) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Can't drop setgid privileges.");
|
|
|
|
exit(1);
|
|
|
|
}
|
2008-09-28 22:06:24 +04:00
|
|
|
#endif
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_main_cleanup(void)
|
|
|
|
{
|
2010-09-23 19:31:24 +04:00
|
|
|
gkrellm_sys_disk_cleanup();
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
/* CPU monitor interface */
|
|
|
|
|
2008-09-28 22:06:24 +04:00
|
|
|
static guint n_cpus;
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_cpu_read_data(void)
|
|
|
|
{
|
|
|
|
processor_cpu_load_info_data_t *pinfo;
|
|
|
|
mach_msg_type_number_t info_count;
|
2010-09-23 19:31:24 +04:00
|
|
|
int i;
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
if (host_processor_info (mach_host_self (),
|
|
|
|
PROCESSOR_CPU_LOAD_INFO,
|
|
|
|
&n_cpus,
|
|
|
|
(processor_info_array_t*)&pinfo,
|
2010-09-23 19:31:24 +04:00
|
|
|
&info_count) != KERN_SUCCESS) {
|
2008-02-01 21:36:15 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < n_cpus; i++) {
|
|
|
|
gkrellm_cpu_assign_data(i,
|
|
|
|
pinfo[i].cpu_ticks [CPU_STATE_USER],
|
|
|
|
pinfo[i].cpu_ticks [CPU_STATE_NICE],
|
|
|
|
pinfo[i].cpu_ticks [CPU_STATE_SYSTEM],
|
|
|
|
pinfo[i].cpu_ticks [CPU_STATE_IDLE]);
|
|
|
|
}
|
|
|
|
vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_cpu_init(void)
|
|
|
|
{
|
|
|
|
processor_cpu_load_info_data_t *pinfo;
|
|
|
|
mach_msg_type_number_t info_count;
|
|
|
|
|
|
|
|
n_cpus = 0;
|
|
|
|
|
|
|
|
if (host_processor_info (mach_host_self (),
|
|
|
|
PROCESSOR_CPU_LOAD_INFO,
|
|
|
|
&n_cpus,
|
|
|
|
(processor_info_array_t*)&pinfo,
|
2010-09-23 19:31:24 +04:00
|
|
|
&info_count) != KERN_SUCCESS) {
|
2008-02-01 21:36:15 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
2010-09-23 19:31:24 +04:00
|
|
|
vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count);
|
2008-02-01 21:36:15 +03:00
|
|
|
gkrellm_cpu_set_number_of_cpus(n_cpus);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
/* Proc monitor interface */
|
|
|
|
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#include <sys/user.h>
|
|
|
|
|
2008-09-28 22:06:24 +04:00
|
|
|
#ifdef HAVE_KVM_H
|
2010-09-23 19:31:24 +04:00
|
|
|
#define PID_MAX 30000
|
2008-02-01 21:36:15 +03:00
|
|
|
#include <kvm.h>
|
2008-09-28 22:06:24 +04:00
|
|
|
#endif
|
2008-02-01 21:36:15 +03:00
|
|
|
#include <limits.h>
|
|
|
|
#include <paths.h>
|
2010-09-23 19:31:24 +04:00
|
|
|
#include <utmpx.h>
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
static int oid_v_forks[CTL_MAXNAME + 2];
|
|
|
|
static int oid_v_vforks[CTL_MAXNAME + 2];
|
|
|
|
static int oid_v_rforks[CTL_MAXNAME + 2];
|
|
|
|
static size_t oid_v_forks_len = sizeof(oid_v_forks);
|
|
|
|
static size_t oid_v_vforks_len = sizeof(oid_v_vforks);
|
|
|
|
static size_t oid_v_rforks_len = sizeof(oid_v_rforks);
|
|
|
|
static int have_v_forks = 0;
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_proc_init(void)
|
|
|
|
{
|
|
|
|
static int oid_name2oid[2] = { 0, 3 };
|
|
|
|
static char *name = "vm.stats.vm.v_forks";
|
|
|
|
static char *vname = "vm.stats.vm.v_vforks";
|
|
|
|
static char *rname = "vm.stats.vm.v_rforks";
|
|
|
|
|
|
|
|
/* check if vm.stats.vm.v_forks is available */
|
|
|
|
if (sysctl(oid_name2oid, 2, oid_v_forks, &oid_v_forks_len,
|
|
|
|
(void *)name, strlen(name)) < 0)
|
|
|
|
return TRUE;
|
|
|
|
if (sysctl(oid_name2oid, 2, oid_v_vforks, &oid_v_vforks_len,
|
|
|
|
(void *)vname, strlen(vname)) < 0)
|
|
|
|
return TRUE;
|
|
|
|
if (sysctl(oid_name2oid, 2, oid_v_rforks, &oid_v_rforks_len,
|
|
|
|
(void *)rname, strlen(rname)) < 0)
|
|
|
|
return TRUE;
|
|
|
|
oid_v_forks_len /= sizeof(int);
|
|
|
|
oid_v_vforks_len /= sizeof(int);
|
|
|
|
oid_v_rforks_len /= sizeof(int);
|
|
|
|
++have_v_forks;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_proc_read_data(void)
|
|
|
|
{
|
|
|
|
static int oid_proc[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
|
|
|
|
double avenrun;
|
2010-09-23 19:31:24 +04:00
|
|
|
static u_int n_processes, n_forks = 0;
|
|
|
|
#ifdef HAVE_KVM_H
|
|
|
|
static u_int curpid = -1;
|
|
|
|
#endif
|
2008-02-01 21:36:15 +03:00
|
|
|
u_int n_vforks, n_rforks;
|
|
|
|
gint r_forks, r_vforks, r_rforks;
|
|
|
|
size_t len;
|
2008-09-28 22:06:24 +04:00
|
|
|
#ifdef HAVE_KVM_H
|
2008-02-01 21:36:15 +03:00
|
|
|
gint nextpid, nforked;
|
|
|
|
static struct nlist nl[] = {
|
|
|
|
#define N_NEXTPID 0
|
|
|
|
{ "_nextpid" },
|
|
|
|
{ "" }
|
|
|
|
};
|
2008-09-28 22:06:24 +04:00
|
|
|
#endif
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
if (getloadavg(&avenrun, 1) <= 0)
|
|
|
|
avenrun = 0;
|
|
|
|
|
|
|
|
if (have_v_forks)
|
|
|
|
{
|
|
|
|
/* We don't want to just use sysctlbyname(). Because,
|
|
|
|
* we call it so often. */
|
|
|
|
len = sizeof(n_forks);
|
|
|
|
r_forks = sysctl(oid_v_forks, oid_v_forks_len,
|
|
|
|
&n_forks, &len, NULL, 0);
|
|
|
|
len = sizeof(n_vforks);
|
|
|
|
r_vforks = sysctl(oid_v_vforks, oid_v_vforks_len,
|
|
|
|
&n_vforks, &len, NULL, 0);
|
|
|
|
len = sizeof(n_rforks);
|
|
|
|
r_rforks = sysctl(oid_v_rforks, oid_v_rforks_len,
|
|
|
|
&n_rforks, &len, NULL, 0);
|
|
|
|
if (r_forks >= 0 && r_vforks >= 0 && r_rforks >= 0)
|
|
|
|
n_forks = n_forks + n_vforks + n_rforks;
|
|
|
|
}
|
2008-09-28 22:06:24 +04:00
|
|
|
#ifdef HAVE_KVM_H
|
2008-02-01 21:36:15 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* workaround: Can I get total number of processes? */
|
|
|
|
if (kvmd != NULL)
|
|
|
|
{
|
|
|
|
if (nl[0].n_type == 0)
|
|
|
|
kvm_nlist(kvmd, nl);
|
|
|
|
if (nl[0].n_type != 0 &&
|
|
|
|
kvm_read(kvmd, nl[N_NEXTPID].n_value,
|
|
|
|
(char *)&nextpid,
|
|
|
|
sizeof(nextpid)) == sizeof(nextpid))
|
|
|
|
{
|
|
|
|
if (curpid < 0)
|
|
|
|
curpid = nextpid;
|
|
|
|
if ((nforked = nextpid - curpid) < 0)
|
|
|
|
n_forks += PID_MAX - 100;
|
|
|
|
n_forks += nforked;
|
|
|
|
curpid = nextpid;
|
|
|
|
n_forks = n_forks;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-09-28 22:06:24 +04:00
|
|
|
#endif
|
|
|
|
|
2008-02-01 21:36:15 +03:00
|
|
|
if (sysctl(oid_proc, 3, NULL, &len, NULL, 0) >= 0)
|
|
|
|
n_processes = len / sizeof(struct kinfo_proc);
|
|
|
|
|
|
|
|
gkrellm_proc_assign_data(n_processes, 0, n_forks, avenrun);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_proc_read_users(void)
|
|
|
|
{
|
2010-09-23 19:31:24 +04:00
|
|
|
struct utmpx *utmpx_entry;
|
|
|
|
gchar ttybuf[MAXPATHLEN];
|
|
|
|
struct stat sb;
|
|
|
|
gint n_users;
|
|
|
|
|
|
|
|
n_users = 0;
|
|
|
|
setutxent();
|
|
|
|
while((utmpx_entry = getutxent()))
|
|
|
|
{
|
|
|
|
if (utmpx_entry->ut_type != USER_PROCESS)
|
|
|
|
continue; // skip other entries (reboot, runlevel changes etc.)
|
|
|
|
|
|
|
|
(void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s",
|
|
|
|
_PATH_DEV, utmpx_entry->ut_line);
|
|
|
|
|
|
|
|
if (stat(ttybuf, &sb))
|
|
|
|
continue; // tty of entry missing, no real user
|
|
|
|
|
|
|
|
++n_users;
|
|
|
|
|
|
|
|
}
|
|
|
|
endutxent();
|
|
|
|
gkrellm_proc_assign_users(n_users);
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
/* Disk monitor interface */
|
|
|
|
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#include <IOKit/IOKitLib.h>
|
2010-09-23 19:31:24 +04:00
|
|
|
#include <IOKit/storage/IOBlockStorageDevice.h>
|
2008-02-01 21:36:15 +03:00
|
|
|
#include <IOKit/storage/IOBlockStorageDriver.h>
|
2010-09-23 19:31:24 +04:00
|
|
|
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _GK_DISK
|
|
|
|
{
|
|
|
|
io_service_t service;
|
|
|
|
io_string_t path;
|
|
|
|
} GK_DARWIN_DISK;
|
|
|
|
|
|
|
|
static GPtrArray *s_disk_ptr_array = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
static GK_DARWIN_DISK *
|
|
|
|
gk_darwin_disk_new()
|
|
|
|
{
|
|
|
|
return g_new0(GK_DARWIN_DISK, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gk_darwin_disk_free(GK_DARWIN_DISK *disk)
|
|
|
|
{
|
|
|
|
if (disk->service != MACH_PORT_NULL)
|
|
|
|
IOObjectRelease(disk->service);
|
|
|
|
g_free(disk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
dict_get_int64(CFDictionaryRef dict, CFStringRef key, gint64 *value)
|
|
|
|
{
|
|
|
|
CFNumberRef number_ref;
|
|
|
|
|
|
|
|
number_ref = (CFNumberRef) CFDictionaryGetValue(dict, key);
|
|
|
|
if ((NULL == number_ref) ||
|
|
|
|
!CFNumberGetValue(number_ref, kCFNumberSInt64Type, value))
|
|
|
|
{
|
|
|
|
*value = 0;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
dict_get_string(CFDictionaryRef dict, CFStringRef key, char *buf, size_t buf_len)
|
|
|
|
{
|
|
|
|
CFStringRef string_ref;
|
|
|
|
|
|
|
|
string_ref = (CFStringRef)CFDictionaryGetValue(dict, key);
|
|
|
|
if ((NULL == string_ref) ||
|
|
|
|
!CFStringGetCString(string_ref, buf, buf_len, kCFStringEncodingUTF8))
|
|
|
|
{
|
|
|
|
buf[0] = '\0';
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
add_storage_device(io_registry_entry_t service)
|
|
|
|
{
|
|
|
|
GK_DARWIN_DISK *disk;
|
|
|
|
CFMutableDictionaryRef chars_dict; /* needs release */
|
|
|
|
gchar vendor_str[128];
|
|
|
|
gchar product_str[128];
|
|
|
|
gchar *disk_label;
|
|
|
|
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP, "add_storage_device(); START\n");
|
|
|
|
|
|
|
|
disk = gk_darwin_disk_new();
|
|
|
|
disk->service = service;
|
|
|
|
|
|
|
|
if (IORegistryEntryGetPath(service, kIOServicePlane, disk->path)
|
|
|
|
!= kIOReturnSuccess)
|
|
|
|
{
|
|
|
|
g_warning("Could not fetch io registry path for disk\n");
|
|
|
|
gk_darwin_disk_free(disk);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
chars_dict = (CFMutableDictionaryRef)IORegistryEntryCreateCFProperty(
|
|
|
|
service, CFSTR(kIOPropertyDeviceCharacteristicsKey),
|
|
|
|
kCFAllocatorDefault, 0);
|
|
|
|
|
|
|
|
if (NULL == chars_dict)
|
|
|
|
{
|
|
|
|
g_warning("Could not fetch properties for disk\n");
|
|
|
|
gk_darwin_disk_free(disk);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP, "Getting vendor name\n");
|
|
|
|
dict_get_string(chars_dict, CFSTR(kIOPropertyVendorNameKey),
|
|
|
|
vendor_str, sizeof(vendor_str));
|
|
|
|
g_strstrip(vendor_str); // remove leading/trailing whitespace
|
|
|
|
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP, "Getting product name\n");
|
|
|
|
dict_get_string(chars_dict, CFSTR(kIOPropertyProductNameKey),
|
|
|
|
product_str, sizeof(product_str));
|
|
|
|
g_strstrip(product_str); // remove leading/trailing whitespace
|
|
|
|
|
|
|
|
if (strlen(vendor_str) > 0)
|
|
|
|
disk_label = g_strdup_printf("%s %s", vendor_str, product_str);
|
|
|
|
else
|
|
|
|
disk_label = g_strdup(product_str);
|
|
|
|
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP, "Adding disk '%s' with fancy label '%s'\n",
|
|
|
|
disk->path, disk_label);
|
|
|
|
|
|
|
|
// Add disk to internal list
|
|
|
|
g_ptr_array_add(s_disk_ptr_array, disk);
|
|
|
|
|
|
|
|
// Add disk to gkrellm list
|
|
|
|
gkrellm_disk_add_by_name(disk->path, disk_label);
|
|
|
|
|
|
|
|
/* we don't need to store the label, it is only for GUI display */
|
|
|
|
g_free(disk_label);
|
|
|
|
CFRelease(chars_dict);
|
|
|
|
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP, "add_storage_device(); END\n");
|
|
|
|
return TRUE;
|
|
|
|
}
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
|
|
|
|
gchar *
|
|
|
|
gkrellm_sys_disk_name_from_device(gint device_number, gint unit_number,
|
|
|
|
gint *order)
|
|
|
|
{
|
|
|
|
return NULL; /* Not implemented */
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
2010-10-07 01:38:56 +04:00
|
|
|
gkrellm_sys_disk_order_from_name(const gchar *name)
|
2008-02-01 21:36:15 +03:00
|
|
|
{
|
|
|
|
/* implement this if you want disk charts to show up in a particular
|
|
|
|
| order in gkrellm.
|
|
|
|
*/
|
|
|
|
return -1; /* Not implemented, disks show up in same order as disk_list */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_disk_read_data(void)
|
|
|
|
{
|
2010-09-23 19:31:24 +04:00
|
|
|
int i;
|
|
|
|
GK_DARWIN_DISK *disk;
|
|
|
|
|
|
|
|
for (i = 0; i < s_disk_ptr_array->len; i++)
|
|
|
|
{
|
|
|
|
io_registry_entry_t storage_driver; /* needs release */
|
|
|
|
CFDictionaryRef storage_driver_stats; /* needs release */
|
|
|
|
gint64 bytes_read;
|
|
|
|
gint64 bytes_written;
|
|
|
|
|
|
|
|
disk = (GK_DARWIN_DISK *)g_ptr_array_index(s_disk_ptr_array, i);
|
|
|
|
|
|
|
|
//gkrellm_debug(DEBUG_SYSDEP, "Fetching disk stats for '%s'\n", disk->path);
|
|
|
|
|
|
|
|
/* get subitem of device, has to be some kind of IOStorageDriver */
|
|
|
|
if (IORegistryEntryGetChildEntry(disk->service, kIOServicePlane,
|
|
|
|
&storage_driver) != kIOReturnSuccess)
|
|
|
|
{
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP,
|
|
|
|
"No driver child found in storage device, skipping disk '%s'\n",
|
|
|
|
disk->path);
|
|
|
|
// skip devices that have no driver child
|
|
|
|
continue;
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
|
|
|
|
2010-09-23 19:31:24 +04:00
|
|
|
storage_driver_stats = IORegistryEntryCreateCFProperty(storage_driver,
|
|
|
|
CFSTR(kIOBlockStorageDriverStatisticsKey), kCFAllocatorDefault, 0);
|
|
|
|
|
|
|
|
if (NULL == storage_driver_stats)
|
|
|
|
{
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP,
|
|
|
|
"No statistics dict found in storage driver, skipping disk '%s'\n",
|
|
|
|
disk->path);
|
|
|
|
IOObjectRelease(storage_driver);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Obtain the number of bytes read/written from the drive statistics */
|
|
|
|
if (dict_get_int64(storage_driver_stats,
|
|
|
|
CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey), &bytes_read)
|
|
|
|
&&
|
|
|
|
dict_get_int64(storage_driver_stats,
|
|
|
|
CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey), &bytes_written)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
gkrellm_disk_assign_data_by_name(disk->path, bytes_read,
|
|
|
|
bytes_written, FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP,
|
|
|
|
"could not fetch read/write stats for disk '%s'\n",
|
|
|
|
disk->path);
|
|
|
|
}
|
|
|
|
|
|
|
|
CFRelease(storage_driver_stats);
|
|
|
|
IOObjectRelease(storage_driver);
|
|
|
|
} // for()
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_disk_init(void)
|
|
|
|
{
|
2010-09-23 19:31:24 +04:00
|
|
|
/* needs release */
|
|
|
|
io_iterator_t iter = MACH_PORT_NULL;
|
|
|
|
|
|
|
|
/* needs release (if add_storage_device() failed) */
|
|
|
|
io_service_t service = MACH_PORT_NULL;
|
|
|
|
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP, "gkrellm_sys_disk_init();\n");
|
|
|
|
|
|
|
|
s_disk_ptr_array = g_ptr_array_new();
|
|
|
|
|
|
|
|
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
|
|
|
IOServiceMatching(kIOBlockStorageDeviceClass),
|
|
|
|
&iter) == kIOReturnSuccess)
|
2008-02-01 21:36:15 +03:00
|
|
|
{
|
2010-09-23 19:31:24 +04:00
|
|
|
while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL)
|
2008-02-01 21:36:15 +03:00
|
|
|
{
|
2010-09-23 19:31:24 +04:00
|
|
|
if (!add_storage_device(service))
|
|
|
|
IOObjectRelease(service);
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
2010-09-23 19:31:24 +04:00
|
|
|
IOObjectRelease(iter);
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
2010-09-23 19:31:24 +04:00
|
|
|
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP,
|
|
|
|
"gkrellm_sys_disk_init(); Found %u disk(s) for monitoring.\n",
|
|
|
|
s_disk_ptr_array->len);
|
|
|
|
|
|
|
|
return (s_disk_ptr_array->len == 0 ? FALSE : TRUE);
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
2010-09-23 19:31:24 +04:00
|
|
|
|
|
|
|
static void
|
|
|
|
gkrellm_sys_disk_cleanup(void)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
if (NULL == s_disk_ptr_array)
|
|
|
|
return;
|
|
|
|
gkrellm_debug(DEBUG_SYSDEP,
|
|
|
|
"gkrellm_sys_disk_cleanup() Freeing counters for %u disk(s)\n",
|
|
|
|
s_disk_ptr_array->len);
|
|
|
|
for (i = 0; i < s_disk_ptr_array->len; i++)
|
|
|
|
gk_darwin_disk_free(g_ptr_array_index(s_disk_ptr_array, i));
|
|
|
|
g_ptr_array_free(s_disk_ptr_array, TRUE);
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
|
|
|
|
2010-09-23 19:31:24 +04:00
|
|
|
/* ===================================================================== */
|
|
|
|
/* Inet monitor interface */
|
2008-02-01 21:36:15 +03:00
|
|
|
|
2008-09-28 22:06:24 +04:00
|
|
|
#include "../inet.h"
|
|
|
|
|
|
|
|
#include <net/route.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#ifdef INET6
|
|
|
|
#include <netinet/ip6.h>
|
|
|
|
#endif /* INET6 */
|
|
|
|
#include <netinet/in_pcb.h>
|
|
|
|
#include <netinet/ip_icmp.h>
|
|
|
|
#include <netinet/icmp_var.h>
|
|
|
|
#include <netinet/igmp_var.h>
|
|
|
|
#include <netinet/ip_var.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <netinet/tcpip.h>
|
|
|
|
#include <netinet/tcp_seq.h>
|
|
|
|
#define TCPSTATES
|
|
|
|
#include <netinet/tcp_fsm.h>
|
|
|
|
#include <netinet/tcp_var.h>
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/udp_var.h>
|
|
|
|
#include <sys/types.h>
|
2008-02-01 21:36:15 +03:00
|
|
|
|
2008-09-28 22:06:24 +04:00
|
|
|
void
|
|
|
|
gkrellm_sys_inet_read_tcp_data(void)
|
|
|
|
{
|
|
|
|
ActiveTCP tcp;
|
|
|
|
const char *mibvar="net.inet.tcp.pcblist";
|
|
|
|
char *buf;
|
|
|
|
struct tcpcb *tp = NULL;
|
|
|
|
struct inpcb *inp;
|
|
|
|
struct xinpgen *xig, *oxig;
|
|
|
|
struct xsocket *so;
|
|
|
|
size_t len=0;
|
|
|
|
if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
|
|
|
|
if (errno != ENOENT)
|
2010-09-23 19:31:24 +04:00
|
|
|
g_warning("sysctl: %s\n", mibvar);
|
2008-09-28 22:06:24 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((buf = malloc(len)) == 0) {
|
2010-09-23 19:31:24 +04:00
|
|
|
g_warning("malloc %lu bytes\n", (u_long)len);
|
2008-09-28 22:06:24 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
|
2010-09-23 19:31:24 +04:00
|
|
|
g_warning("sysctl: %s\n", mibvar);
|
2008-09-28 22:06:24 +04:00
|
|
|
free(buf);
|
|
|
|
return;
|
2008-02-01 21:36:15 +03:00
|
|
|
}
|
2008-09-28 22:06:24 +04:00
|
|
|
/*
|
|
|
|
* Bail-out to avoid logic error in the loop below when
|
|
|
|
* there is in fact no more control block to process
|
|
|
|
*/
|
|
|
|
if (len <= sizeof(struct xinpgen)) {
|
|
|
|
free(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
oxig = xig = (struct xinpgen *)buf;
|
|
|
|
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
|
|
|
|
xig->xig_len > sizeof(struct xinpgen);
|
|
|
|
xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
|
|
|
|
tp = &((struct xtcpcb *)xig)->xt_tp;
|
|
|
|
inp = &((struct xtcpcb *)xig)->xt_inp;
|
|
|
|
so = &((struct xtcpcb *)xig)->xt_socket;
|
|
|
|
if (so->xso_protocol != IPPROTO_TCP)
|
|
|
|
continue;
|
|
|
|
/* Ignore PCBs which were freed during copyout. */
|
|
|
|
if (inp->inp_gencnt > oxig->xig_gen)
|
|
|
|
continue;
|
|
|
|
if ((inp->inp_vflag & INP_IPV4) == 0
|
|
|
|
#ifdef INET6
|
|
|
|
&& (inp->inp_vflag & INP_IPV6) == 0
|
|
|
|
#endif /* INET6 */
|
|
|
|
)
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Local address is not an indication of listening socket or
|
|
|
|
* server sockey but just rather the socket has been bound.
|
|
|
|
* That why many UDP sockets were not displayed in the original code.
|
|
|
|
*/
|
|
|
|
if (tp->t_state <= TCPS_LISTEN){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (inp->inp_vflag & INP_IPV4) {
|
|
|
|
tcp.local_port=ntohs(inp->inp_lport);
|
|
|
|
tcp.remote_addr.s_addr=(uint32_t)inp->inp_faddr.s_addr;
|
|
|
|
tcp.remote_port=ntohs(inp->inp_fport);
|
|
|
|
tcp.family=AF_INET;
|
|
|
|
gkrellm_inet_log_tcp_port_data(&tcp);
|
|
|
|
}
|
|
|
|
#ifdef INET6
|
|
|
|
else if (inp->inp_vflag & INP_IPV6) {
|
|
|
|
tcp.local_port=ntohs(inp->inp_lport);
|
|
|
|
memcpy(&(tcp.remote_addr6),&(inp->in6p_faddr),sizeof(struct in6_addr));
|
|
|
|
tcp.remote_port=ntohs(inp->inp_fport);
|
|
|
|
tcp.family=AF_INET6;
|
|
|
|
gkrellm_inet_log_tcp_port_data(&tcp);
|
|
|
|
} /* else nothing printed now */
|
|
|
|
#endif /* INET6 */
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_inet_init(void)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
/* Memory/Swap monitor interface */
|
|
|
|
|
|
|
|
#include <mach/mach_init.h>
|
|
|
|
#include <mach/mach_host.h>
|
|
|
|
#include <mach/host_info.h>
|
|
|
|
#include <mach/mach_error.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <mach/mach_types.h>
|
|
|
|
#include <mach/machine/vm_param.h>
|
|
|
|
|
|
|
|
static guint64 swapin,
|
|
|
|
swapout,
|
|
|
|
swap_total,
|
|
|
|
swap_used;
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_mem_read_data(void)
|
|
|
|
{
|
|
|
|
static gint psize, pshift, first_time_done = 0;
|
|
|
|
vm_statistics_data_t vm_info;
|
|
|
|
mach_msg_type_number_t info_count;
|
|
|
|
kern_return_t error;
|
|
|
|
static DIR *dirp;
|
|
|
|
struct dirent *dp;
|
|
|
|
guint64 total, used, free, shared, buffers, cached;
|
|
|
|
|
|
|
|
info_count = HOST_VM_INFO_COUNT;
|
|
|
|
|
|
|
|
error = host_statistics (mach_host_self (), HOST_VM_INFO, (host_info_t)&vm_info, &info_count);
|
|
|
|
if (error != KERN_SUCCESS)
|
|
|
|
{
|
|
|
|
mach_error("host_info", error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pshift == 0)
|
|
|
|
{
|
|
|
|
for (psize = getpagesize(); psize > 1; psize >>= 1)
|
|
|
|
pshift++;
|
|
|
|
}
|
|
|
|
|
2008-09-28 22:06:24 +04:00
|
|
|
used = (guint64)(vm_info.active_count) << pshift;
|
|
|
|
free = (guint64)vm_info.free_count << pshift;
|
|
|
|
total = (guint64)(vm_info.active_count + vm_info.inactive_count + vm_info.free_count + vm_info.wire_count) << pshift;
|
2008-02-01 21:36:15 +03:00
|
|
|
/* Don't know how to get cached or buffers. */
|
2008-09-28 22:06:24 +04:00
|
|
|
buffers = (guint64) (vm_info.wire_count) << pshift;
|
|
|
|
cached = (guint64) (vm_info.inactive_count) << pshift;
|
2008-02-01 21:36:15 +03:00
|
|
|
/* shared 0 for now, shared is a PITA */
|
|
|
|
shared = 0;
|
|
|
|
gkrellm_mem_assign_data(total, used, free, shared, buffers, cached);
|
|
|
|
|
|
|
|
/* Swap is available at same time as mem, so grab values here.
|
|
|
|
*/
|
|
|
|
swapin = vm_info.pageins;
|
|
|
|
swapout = vm_info.pageouts;
|
|
|
|
swap_used = vm_info.pageouts << pshift;
|
|
|
|
|
|
|
|
/* Figure out total swap. This adds up the size of the swapfiles */
|
|
|
|
if (!first_time_done)
|
|
|
|
{
|
|
|
|
dirp = opendir ("/private/var/vm");
|
|
|
|
if (!dirp)
|
|
|
|
return;
|
|
|
|
++first_time_done;
|
|
|
|
}
|
|
|
|
swap_total = 0;
|
|
|
|
while ((dp = readdir (dirp)) != NULL) {
|
|
|
|
struct stat sb;
|
|
|
|
char fname [MAXNAMLEN];
|
|
|
|
if (strncmp (dp->d_name, "swapfile", 8))
|
|
|
|
continue;
|
|
|
|
strcpy (fname, "/private/var/vm/");
|
|
|
|
strcat (fname, dp->d_name);
|
|
|
|
if (stat (fname, &sb) < 0)
|
|
|
|
continue;
|
|
|
|
swap_total += sb.st_size;
|
|
|
|
}
|
|
|
|
/* Save overhead, leave it open. where can we close it? */
|
|
|
|
rewinddir(dirp);
|
|
|
|
/* closedir (dirp); */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_swap_read_data(void)
|
|
|
|
{
|
|
|
|
gkrellm_swap_assign_data(swap_total, swap_used, swapin, swapout);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_mem_init(void)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
/* Battery monitor interface - not implemented */
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_sys_battery_read_data(void)
|
|
|
|
{
|
|
|
|
// gkrellm_battery_assign_data(0, available, on_line, charging,
|
|
|
|
// percent, time_left);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_battery_init(void)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
/* Sensor monitor interface - not implemented */
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_sensors_get_temperature(gchar *path, gint id,
|
|
|
|
gint iodev, gint interface, gfloat *temp)
|
|
|
|
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_sensors_get_fan(gchar *path, gint id,
|
|
|
|
gint iodev, gint interface, gfloat *fan)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_sensors_get_voltage(gchar *path, gint id,
|
|
|
|
gint iodev, gint interface, gfloat *volt)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gkrellm_sys_sensors_init(void)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|