gkrellm/src/sysdeps/netbsd.c

816 lines
21 KiB
C
Raw Normal View History

2008-02-01 21:36:15 +03:00
/* GKrellM
| 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
|
| netbsd.c code is Copyright (C):
| Anthony Mallet <anthony.mallet@useless-ficus.net>
|
|
| 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/
|
|
| 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
*/
#include <kvm.h>
kvm_t *kvmd = NULL;
char errbuf[_POSIX2_LINE_MAX];
void
gkrellm_sys_main_init(void)
{
/* 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);
}
}
void
gkrellm_sys_main_cleanup(void)
{
}
/* ===================================================================== */
/* CPU monitor interface */
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/sched.h>
static gint ncpus;
static gint get_ncpus(void);
void
gkrellm_sys_cpu_read_data(void)
{
static int mib[] = { CTL_KERN, KERN_CP_TIME };
u_int64_t cp_time[ncpus][CPUSTATES];
int n;
size_t len;
if (ncpus > 1) {
len = sizeof(cp_time[0]);
/* The sysctl() is magic -- it returns the aggregate if
there's not enough room for all CPU's. */
if (sysctl(mib, 2, cp_time, &len, NULL, 0) == 0)
gkrellm_cpu_assign_composite_data(cp_time[0][CP_USER],
cp_time[0][CP_NICE], cp_time[0][CP_SYS], cp_time[0][CP_IDLE]);
}
len = sizeof(cp_time);
if (sysctl(mib, 2, cp_time, &len, NULL, 0) < 0) return;
for (n = 0; n < ncpus; n++)
gkrellm_cpu_assign_data(n, cp_time[n][CP_USER],
cp_time[n][CP_NICE], cp_time[n][CP_SYS], cp_time[n][CP_IDLE]);
}
gboolean
gkrellm_sys_cpu_init(void)
{
ncpus = get_ncpus();
gkrellm_cpu_set_number_of_cpus(ncpus);
return TRUE;
}
static gint
get_ncpus(void)
{
static int mib[] = { CTL_HW, HW_NCPU };
int ncpus;
size_t len = sizeof(int);
if (sysctl(mib, 2, &ncpus, &len, NULL, 0) < 0)
return 1;
else
return ncpus;
}
/* ===================================================================== */
/* Proc monitor interface */
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <uvm/uvm_extern.h>
#include <utmp.h>
void
gkrellm_sys_proc_read_data(void)
{
int mib[6];
double avenrun;
guint n_forks = 0, n_processes = 0;
struct uvmexp_sysctl uvmexp;
size_t size;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC2;
mib[2] = KERN_PROC_ALL;
mib[3] = 0;
mib[4] = sizeof(struct kinfo_proc2);
mib[5] = 0;
if (sysctl(mib, 6, NULL, &size, NULL, 0) >= 0) {
n_processes = size / sizeof(struct kinfo_proc2);
}
mib[0] = CTL_VM;
mib[1] = VM_UVMEXP2;
size = sizeof(uvmexp);
if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) >= 0) {
n_forks = uvmexp.forks;
}
if (getloadavg(&avenrun, 1) <= 0)
avenrun = 0;
gkrellm_proc_assign_data(n_processes, 0, n_forks, avenrun);
}
void
gkrellm_sys_proc_read_users(void)
{
gint n_users;
static time_t utmp_mtime;
struct utmp utmp;
struct stat s;
FILE *ut;
if (stat(_PATH_UTMP, &s) == 0 && s.st_mtime != utmp_mtime)
{
if ((ut = fopen(_PATH_UTMP, "r")) != NULL)
{
n_users = 0;
while (fread(&utmp, sizeof(utmp), 1, ut))
{
if (utmp.ut_name[0] == '\0') continue;
++n_users;
}
(void)fclose(ut);
gkrellm_proc_assign_users(n_users);
}
utmp_mtime = s.st_mtime;
}
}
gboolean
gkrellm_sys_proc_init(void)
{
return TRUE;
}
/* ===================================================================== */
/* Memory/Swap monitor interface */
#include <sys/vmmeter.h>
#include <sys/sysctl.h>
#include <uvm/uvm_extern.h>
void
gkrellm_sys_mem_read_data(void)
{
int mib[2];
guint64 total, used, free, shared, buffers, cached;
struct vmtotal vmt;
struct uvmexp_sysctl uvmexp;
size_t len;
mib[0] = CTL_VM;
mib[1] = VM_METER;
len = sizeof(vmt);
if (sysctl(mib, 2, &vmt, &len, NULL, 0) < 0)
memset(&vmt, 0, sizeof(vmt));
mib[0] = CTL_VM;
mib[1] = VM_UVMEXP2;
len = sizeof(uvmexp);
if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0)
memset(&uvmexp, 0, sizeof(uvmexp));
total = uvmexp.npages << uvmexp.pageshift;
/* not sure of what must be computed */
free = (uvmexp.inactive + uvmexp.free) << uvmexp.pageshift;
shared = vmt.t_rmshr << uvmexp.pageshift;
/* can't use "uvmexp.active << uvmexp.pageshift" here because the
* display for "free" uses "total - used" which is very wrong. */
used = total - free;
/* don't know how to get those values */
buffers = 0;
cached = 0;
gkrellm_mem_assign_data(total, used, free, shared, buffers, cached);
}
void
gkrellm_sys_swap_read_data(void)
{
static int pgout, pgin;
int mib[2];
struct uvmexp_sysctl uvmexp;
size_t len;
static gulong swapin = 0, swapout = 0;
guint64 swap_total, swap_used;
mib[0] = CTL_VM;
mib[1] = VM_UVMEXP2;
len = sizeof(uvmexp);
if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0)
memset(&uvmexp, 0, sizeof(uvmexp));
/* show only the pages located on the disk and not in memory */
swap_total = (guint64) (uvmexp.swpages << uvmexp.pageshift);
swap_used = (guint64) (uvmexp.swpgonly << uvmexp.pageshift);
/* For page in/out operations, uvmexp struct doesn't seem to be reliable */
/* if the number of swapped pages that are in memory (inuse - only) is
* greater that the previous value (pgin), we count this a "page in" */
if (uvmexp.swpginuse - uvmexp.swpgonly > pgin)
swapin += uvmexp.swpginuse - uvmexp.swpgonly - pgin;
pgin = uvmexp.swpginuse - uvmexp.swpgonly;
/* same for page out */
if (uvmexp.swpgonly > pgout)
swapout += uvmexp.swpgonly - pgout;
pgout = uvmexp.swpgonly;
gkrellm_swap_assign_data(swap_total, swap_used, swapin, swapout);
}
gboolean
gkrellm_sys_mem_init(void)
{
return TRUE;
}
/* ===================================================================== */
/* Sensor monitor interface */
/* Tables of voltage correction factors and offsets derived from the
| compute lines in sensors.conf. See the README file.
*/
/* "lm78-*" "lm78-j-*" "lm79-*" "w83781d-*" "sis5595-*" "as99127f-*" */
/* Values from LM78/LM79 data sheets */
#if 0
static VoltDefault voltdefault0[] =
{
{ "Vcor1", 1.0, 0, NULL },
{ "Vcor2", 1.0, 0, NULL },
{ "+3.3V", 1.0, 0, NULL },
{ "+5V", 1.68, 0, NULL }, /* in3 ((6.8/10)+1)*@ */
{ "+12V", 4.0, 0, NULL }, /* in4 ((30/10)+1)*@ */
{ "-12V", -4.0, 0, NULL }, /* in5 -(240/60)*@ */
{ "-5V", -1.667, 0, NULL } /* in6 -(100/60)*@ */
};
#endif
/* The SENSORS_DIR is not defined as a directory, but directly points on
* the "sysmon" device, which implements envsys(4) API. This #define is
* not really useful for NetBSD since every sensor will use that device,
* but it still provides the location of the device inside the GUI. */
#define SENSORS_DIR "/dev/sysmon"
#include <sys/envsys.h>
/*
* get_netbsd_sensor ----------------------------------------------------
*
* Perform sensor reading
*/
#include <sys/ioctl.h>
gboolean
gkrellm_sys_sensors_get_temperature(gchar *path, gint id,
gint iodev, gint interface, gfloat *temp)
{
envsys_tre_data_t data; /* sensor data */
data.sensor = interface;
if (ioctl(iodev, ENVSYS_GTREDATA, &data) < 0) return FALSE;
if (!(data.validflags & (ENVSYS_FVALID|ENVSYS_FCURVALID))) return FALSE;
if (data.units == ENVSYS_STEMP) {
if (temp) /* values in uK */
*temp = (data.cur.data_us / 1.0e6) - 273.15/*0K*/ ;
return TRUE;
}
return FALSE;
}
gboolean
gkrellm_sys_sensors_get_fan(gchar *path, gint id,
gint iodev, gint interface, gfloat *fan)
{
envsys_tre_data_t data; /* sensor data */
data.sensor = interface;
if (ioctl(iodev, ENVSYS_GTREDATA, &data) < 0) return FALSE;
if (!(data.validflags & (ENVSYS_FVALID|ENVSYS_FCURVALID))) return FALSE;
if (data.units == ENVSYS_SFANRPM) {
if (fan) /* values in RPM */
*fan = data.cur.data_us;
return TRUE;
}
return FALSE;
}
gboolean
gkrellm_sys_sensors_get_voltage(gchar *path, gint id,
gint iodev, gint interface, gfloat *volt)
{
envsys_tre_data_t data; /* sensor data */
data.sensor = interface;
if (ioctl(iodev, ENVSYS_GTREDATA, &data) < 0) return FALSE;
if (!(data.validflags & (ENVSYS_FVALID|ENVSYS_FCURVALID))) return FALSE;
if (data.units == ENVSYS_SVOLTS_DC) {
if (volt) /* values in uV */
*volt = data.cur.data_s / 1.0e6;
return TRUE;
}
return FALSE;
}
/*
*
* At the moment, only two chips are supported: lm78 and alike (see
* lm(4)), and VT82C68A South Bridge for VIA chipsets (see viaenv(4)).
* Both support the envsys(4) API.
*
* XXX /dev/sysmon is opened but never closed. This is a problem since
* the driver wants an exclusive lock (e.g. envstat won't work when
* GKrellM will be running). But, at this time, I don't want to
* open/close sysmon each time a reading is needed. See README for
* details.
*/
gboolean
gkrellm_sys_sensors_init(void)
{
envsys_basic_info_t info; /* sensor misc. info */
int fd; /* file desc. for /dev/sysmon */
int id = 0; /* incremented for each sensor */
int type;
char *s, base_name[33];
gboolean found_sensors = FALSE;
/* check if some sensor is configured */
fd = open(SENSORS_DIR, O_RDONLY); /* never closed */
if (fd < 0) return FALSE;
/* iterate through available sensors, until the first invalid */
for(info.sensor=0; ; info.sensor++) {
/* stop if we can't ioctl() */
if (ioctl(fd, ENVSYS_GTREINFO, &info) < 0) break;
/* stop if that sensor is not valid */
if (!(info.validflags & ENVSYS_FVALID)) break;
switch(info.units) {
case ENVSYS_STEMP:
type = SENSOR_TEMPERATURE; break;
case ENVSYS_SFANRPM:
type = SENSOR_FAN; break;
case ENVSYS_SVOLTS_DC:
type = SENSOR_VOLTAGE; break;
default:
/* unwanted sensor type: continue */
continue;
}
/* ok, we've got one working sensor */
sprintf(base_name, "%32s", info.desc);
/* must map spaces into something else (for config file items) */
for(s=strchr(base_name, ' '); s != NULL; s=strchr(s, ' '))
*s++ = '_';
gkrellm_sensors_add_sensor(type, SENSORS_DIR, base_name,
id, fd, info.sensor, 1.0,
0.0, NULL, NULL);
found_sensors = TRUE;
}
return found_sensors;
}
/* ===================================================================== */
/* Battery monitor interface */
#if defined(__i386__) || defined(__powerpc__)
# include <sys/ioctl.h>
# include <machine/apmvar.h>
# define APMDEV "/dev/apm"
#endif
static int battery_use_apm = 1;
/* battery data, index by [battery number] */
static struct battery_acpi_data {
gboolean available; int available_index;
gboolean on_line; int on_line_index;
gboolean charging; int charging_index;
gint full_cap; int full_cap_index;
gint cap; int cap_index;
gint discharge_rate; int discharge_rate_index;
gint charge_rate; int charge_rate_index;
} *battery_acpi_data;
static int battery_acpi_data_items;
static int
gkrellm_battery_data_alloc(int bat)
{
if (bat + 1 > battery_acpi_data_items)
battery_acpi_data_items = bat + 1;
battery_acpi_data = realloc(battery_acpi_data,
battery_acpi_data_items*
sizeof(*battery_acpi_data));
return battery_acpi_data?1:0;
}
void
gkrellm_sys_battery_read_data(void)
{
int i;
int fd; /* file desc. for /dev/sysmon or /dev/apm */
envsys_tre_data_t data; /* sensor data */
int time_left;
if (battery_use_apm) {
#if defined(__i386__) || defined(__powerpc__)
int r;
struct apm_power_info apminfo;
gboolean available, on_line, charging;
gint percent, time_left;
if ((fd = open(APMDEV, O_RDONLY)) == -1) return;
memset(&apminfo, 0, sizeof(apminfo));
r = ioctl(fd, APM_IOC_GETPOWER, &apminfo);
close(fd);
if (r == -1) return;
available = (apminfo.battery_state != APM_BATT_UNKNOWN);
on_line = (apminfo.ac_state == APM_AC_ON) ? TRUE : FALSE;
charging = (apminfo.battery_state == APM_BATT_CHARGING) ? TRUE : FALSE;
percent = apminfo.battery_life;
time_left = apminfo.minutes_left;
gkrellm_battery_assign_data(0, available, on_line, charging,
percent, time_left);
#else
return;
#endif
}
fd = open(SENSORS_DIR, O_RDONLY);
if (fd < 0) return;
data.sensor = battery_acpi_data[0].on_line_index;
if (ioctl(fd, ENVSYS_GTREDATA, &data) < 0) return;
if (!(data.validflags & ENVSYS_FVALID)) return;
battery_acpi_data[0].on_line = data.cur.data_us ? TRUE:FALSE;
/* iterate through available batteries */
for(i=0; i<battery_acpi_data_items; i++) {
#define read_sensor(x) \
do { \
data.sensor = battery_acpi_data[i].x ## _index; \
if (ioctl(fd, ENVSYS_GTREDATA, &data) < 0) continue; \
if (!(data.validflags & ENVSYS_FCURVALID)) \
battery_acpi_data[i].x = -1; \
else \
battery_acpi_data[i].x = data.cur.data_s; \
} while(0)
read_sensor(available);
read_sensor(charging);
read_sensor(full_cap);
read_sensor(cap);
read_sensor(discharge_rate);
read_sensor(charge_rate);
#undef read_sensor
if (battery_acpi_data[i].discharge_rate > 0)
time_left =
battery_acpi_data[i].cap * 60 / battery_acpi_data[i].discharge_rate;
else if (battery_acpi_data[i].charge_rate > 0)
time_left =
(battery_acpi_data[i].full_cap - battery_acpi_data[i].cap) * 60 /
battery_acpi_data[i].charge_rate;
else
time_left = -1;
if (battery_acpi_data[i].available) {
gkrellm_battery_assign_data(i,
battery_acpi_data[i].available,
battery_acpi_data[0].on_line,
battery_acpi_data[i].charging,
/* percent */
battery_acpi_data[i].cap * 100 /
battery_acpi_data[i].full_cap,
/* time left (minutes) */
time_left);
} else
gkrellm_battery_assign_data(i, 0, 0, 0, -1, -1);
}
close(fd);
}
gboolean
gkrellm_sys_battery_init()
{
int fd; /* file desc. for /dev/sysmon or /dev/apm */
envsys_basic_info_t info; /* sensor misc. info */
gboolean found_sensors = FALSE;
char fake[2];
int r, bat;
/* --- check APM first --- */
#if defined(__i386__) || defined(__powerpc__)
do {
struct apm_power_info info;
if ((fd = open(APMDEV, O_RDONLY)) == -1) break;
r = ioctl(fd, APM_IOC_GETPOWER, &info);
close(fd);
if (r != -1) {
battery_use_apm = 1;
return TRUE;
}
} while(0);
#endif
/* --- check for some envsys(4) acpi battery --- */
battery_use_apm = 0;
battery_acpi_data_items = 0;
battery_acpi_data = NULL; /* this is never freed */
fd = open(SENSORS_DIR, O_RDONLY);
if (fd < 0) return FALSE;
/* iterate through available sensors */
for(info.sensor=0; ; info.sensor++) {
/* stop if we can't ioctl() */
if (ioctl(fd, ENVSYS_GTREINFO, &info) < 0) break;
/* stop if that sensor is not valid */
if (!(info.validflags & ENVSYS_FVALID)) break;
do {
if (info.units == ENVSYS_INDICATOR &&
sscanf(info.desc, "acpibat%d presen%1[t]", &bat, fake) == 2) {
if (!gkrellm_battery_data_alloc(bat)) return FALSE;
battery_acpi_data[bat].available_index = info.sensor;
found_sensors = TRUE;
} else if (info.units == ENVSYS_INDICATOR &&
sscanf(info.desc, "acpiacad%*d connecte%1[d]", fake) == 1) {
if (!gkrellm_battery_data_alloc(0)) return FALSE;
battery_acpi_data[0].on_line_index = info.sensor;
} else if (info.units == ENVSYS_INDICATOR &&
sscanf(info.desc,
"acpibat%d chargin%1[g]", &bat, fake) == 2) {
if (!gkrellm_battery_data_alloc(bat)) return FALSE;
battery_acpi_data[bat].charging_index = info.sensor;
found_sensors = TRUE;
} else if (info.units == ENVSYS_SAMPHOUR &&
sscanf(info.desc,
"acpibat%d design ca%1[p]", &bat, fake) == 2) {
if (!gkrellm_battery_data_alloc(bat)) return FALSE;
battery_acpi_data[bat].full_cap_index = info.sensor;
found_sensors = TRUE;
} else if (info.units == ENVSYS_SAMPHOUR &&
sscanf(info.desc,
"acpibat%d charg%1[e]", &bat, fake) == 2) {
if (!gkrellm_battery_data_alloc(bat)) return FALSE;
battery_acpi_data[bat].cap_index = info.sensor;
found_sensors = TRUE;
} else if (info.units == ENVSYS_SAMPS &&
sscanf(info.desc,
"acpibat%d discharge rat%1[e]", &bat, fake) == 2) {
if (!gkrellm_battery_data_alloc(bat)) return FALSE;
battery_acpi_data[bat].discharge_rate_index = info.sensor;
found_sensors = TRUE;
} else if (info.units == ENVSYS_SAMPS &&
sscanf(info.desc,
"acpibat%d charge rat%1[e]", &bat, fake) == 2) {
if (!gkrellm_battery_data_alloc(bat)) return FALSE;
battery_acpi_data[bat].charge_rate_index = info.sensor;
found_sensors = TRUE;
}
} while(0);
}
close(fd);
return found_sensors;
}
/* ===================================================================== */
/* Disk monitor interface */
#include <sys/dkstat.h>
#include <sys/disk.h>
#include <sys/sysctl.h>
#ifdef HW_IOSTATS
#define HW_DISKSTATS HW_IOSTATS
#define disk_sysctl io_sysctl
#define dk_rbytes rbytes
#define dk_wbytes wbytes
#define dk_name name
#endif
gboolean
gkrellm_sys_disk_init(void)
{
int mib[3] = { CTL_HW, HW_DISKSTATS, sizeof(struct disk_sysctl) };
size_t size;
/* Just test if the sysctl call works */
if (sysctl(mib, 3, NULL, &size, NULL, 0) == -1)
return (FALSE);
return (TRUE);
}
void
gkrellm_sys_disk_read_data(void)
{
int i, n_disks, mib[3] = { CTL_HW, HW_DISKSTATS, sizeof(struct disk_sysctl) };
size_t size;
guint64 rbytes, wbytes;
struct disk_sysctl *dk_drives;
if (sysctl(mib, 3, NULL, &size, NULL, 0) == -1)
return;
dk_drives = malloc(size);
if (dk_drives == NULL)
return;
n_disks = size / sizeof(struct disk_sysctl);
if (sysctl(mib, 3, dk_drives, &size, NULL, 0) == -1)
return;
for (i = 0; i < n_disks; i++) {
#if __NetBSD_Version__ >= 106110000
rbytes = dk_drives[i].dk_rbytes;
wbytes = dk_drives[i].dk_wbytes;
#else
rbytes = dk_drives[i].dk_bytes;
wbytes = 0;
#endif
gkrellm_disk_assign_data_by_name(dk_drives[i].dk_name, rbytes, wbytes, FALSE);
}
free(dk_drives);
}
gchar *
gkrellm_sys_disk_name_from_device(gint device_number, gint unit_number,
gint *order)
{
return NULL; /* disk data by device 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
{
return -1; /* append disk charts as added */
}
#if __NetBSD_Version__ >= 399000100
#include "../inet.h"
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp_fsm.h>
static const struct gkrellm_inet_fam {
sa_family_t family;
const char *mib;
} families[] = { {AF_INET, "net.inet.tcp.pcblist"},
#ifdef INET6
{AF_INET6, "net.inet6.tcp6.pcblist"},
#endif
{0, NULL} };
void
gkrellm_sys_inet_read_tcp_data()
{
ActiveTCP tcp;
int mib[CTL_MAXNAME], i;
size_t sz;
u_int namelen;
struct kinfo_pcb *pcbt = NULL;
const struct gkrellm_inet_fam *pf = families;
while (pf->mib != NULL) {
sz = CTL_MAXNAME;
if (sysctlnametomib(pf->mib, mib, &sz) == -1)
return;
namelen = sz;
mib[namelen++] = PCB_ALL;
mib[namelen++] = 0;
mib[namelen++] = sizeof(struct kinfo_pcb);
mib[namelen++] = INT_MAX;
sz = 0;
pcbt = NULL;
if (sysctl(&mib[0], namelen, pcbt, &sz, NULL, 0) == -1)
return;
pcbt = malloc(sz);
if (pcbt == NULL)
return;
if (sysctl(&mib[0], namelen, pcbt, &sz, NULL, 0) == -1)
return;
sz /= sizeof(struct kinfo_pcb);
for (i = 0; i < sz; i++) {
tcp.family = pf->family;
if (pf->family == AF_INET) {
struct sockaddr_in *sin =
(struct sockaddr_in *)&pcbt[i].ki_dst;
tcp.remote_addr.s_addr = sin->sin_addr.s_addr;
tcp.remote_port = sin->sin_port;
sin = (struct sockaddr_in *)&pcbt[i].ki_src;
tcp.local_port = sin->sin_port;
#ifdef INET6
} else { /* AF_INET6 */
struct sockaddr_in6 *sin =
(struct sockaddr_in6 *)&pcbt[i].ki_dst;
memcpy(&tcp.remote_addr6, &sin->sin6_addr,
sizeof(struct in6_addr));
tcp.remote_port = sin->sin6_port;
sin = (struct sockaddr_in6 *)&pcbt[i].ki_src;
tcp.local_port = sin->sin6_port;
#endif
}
if (pcbt[i].ki_tstate == TCPS_ESTABLISHED)
gkrellm_inet_log_tcp_port_data(&tcp);
}
free(pcbt);
pf++;
}
}
#endif