experimental erlang driver
This commit is contained in:
parent
0cecd10a4d
commit
22c0d9e356
|
@ -1625,6 +1625,13 @@ $comment
|
|||
EOF
|
||||
}
|
||||
|
||||
sub erl_warning_comment {
|
||||
my $self = shift;
|
||||
my $comment = $self->warning_comment;
|
||||
$comment =~ s/^/% /mg;
|
||||
"$comment\n";
|
||||
}
|
||||
|
||||
sub generate {
|
||||
my($lang, $dir) = @_ ? @_ : @ARGV;
|
||||
|
||||
|
@ -1689,7 +1696,9 @@ sub uptodate {
|
|||
return 1;
|
||||
}
|
||||
|
||||
my(%warning_comment) = map { $_ => \&c_warning_comment } qw(c h java);
|
||||
my(%warning_comment) =
|
||||
((map { $_ => \&c_warning_comment } qw(c h java)),
|
||||
(map { $_ => \&erl_warning_comment } qw(erl hrl)));
|
||||
|
||||
sub create {
|
||||
my($self, $file) = @_;
|
||||
|
@ -2777,6 +2786,168 @@ sub finish {
|
|||
$self->SUPER::finish;
|
||||
}
|
||||
|
||||
package SigarWrapper::Erlang;
|
||||
|
||||
use vars qw(@ISA);
|
||||
@ISA = qw(SigarWrapper);
|
||||
|
||||
my %field_types = (
|
||||
Long => "esigar_encode_ulonglong",
|
||||
Double => "esigar_encode_double",
|
||||
Int => "esigar_encode_long",
|
||||
Char => "esigar_encode_char",
|
||||
String => "esigar_encode_string",
|
||||
NetAddress => "esigar_encode_netaddr",
|
||||
);
|
||||
|
||||
my $c_file = 'priv/gen/sigar_drv_gen.c';
|
||||
my $h_file = 'priv/gen/sigar.hrl';
|
||||
my $g_file = 'priv/gen/sigar_gen.hrl';
|
||||
|
||||
sub sources {
|
||||
return $c_file;
|
||||
}
|
||||
|
||||
sub start {
|
||||
my $self = shift;
|
||||
$self->SUPER::start;
|
||||
$self->{cfh} = $self->create($c_file);
|
||||
$self->{hfh} = $self->create($h_file);
|
||||
$self->{gfh} = $self->create($g_file);
|
||||
}
|
||||
|
||||
sub generate_class {
|
||||
my($self, $func) = @_;
|
||||
|
||||
my $cfh = $self->{cfh};
|
||||
my $cname = $func->{cname};
|
||||
my $parse_args = "";
|
||||
my $vars = "";
|
||||
my $args = 'sigar';
|
||||
|
||||
if ($func->{num_args} == 1) {
|
||||
if ($func->{is_proc}) {
|
||||
$parse_args = 'pid = esigar_pid_get(sigar, bytes);';
|
||||
$vars = "long $func->{arg};\n";
|
||||
}
|
||||
else {
|
||||
$parse_args .= 'name = bytes;';
|
||||
$vars = "char *$func->{arg};\n";
|
||||
}
|
||||
$args .= ", $func->{arg}";
|
||||
}
|
||||
|
||||
my $encoder = "esigar_encode_$cname";
|
||||
my $n = scalar @{ $func->{fields} };
|
||||
|
||||
print $cfh <<EOF;
|
||||
static void $encoder(ei_x_buff *x,
|
||||
$func->{sigar_type} *$cname)
|
||||
{
|
||||
ei_x_encode_list_header(x, $n);
|
||||
EOF
|
||||
|
||||
for my $field (@{ $func->{fields} }) {
|
||||
my $name = $field->{name};
|
||||
my $type = $field_types{ $field->{type} };
|
||||
|
||||
print $cfh qq{ $type(x, "$name", $cname->$name);\n};
|
||||
}
|
||||
|
||||
print $cfh " ei_x_encode_empty_list(x);\n}\n\n";
|
||||
|
||||
print $cfh <<EOF if $func->{has_get};
|
||||
static int e$func->{sigar_function}(ErlDrvPort port, sigar_t *sigar, char *bytes)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
$func->{sigar_type} $cname;
|
||||
$vars
|
||||
$parse_args
|
||||
|
||||
ESIGAR_NEW(&x);
|
||||
if ((status = $func->{sigar_function}($args, &$cname)) == SIGAR_OK) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
$encoder(&x, &$cname);
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
my(@nongens) =
|
||||
qw{net_interface_list net_route_list net_connection_list
|
||||
file_system_list cpu_info_list who_list
|
||||
loadavg};
|
||||
|
||||
sub finish {
|
||||
my $self = shift;
|
||||
|
||||
my $mappings = $self->get_mappings;
|
||||
my $cfh = $self->{cfh};
|
||||
my $hfh = $self->{hfh};
|
||||
my $gfh = $self->{gfh};
|
||||
my $ncmd = 1;
|
||||
|
||||
for my $ngen (@nongens) {
|
||||
my $cmd = uc $ngen;
|
||||
print $cfh "#define ESIGAR_$cmd $ncmd\n";
|
||||
print $hfh "-define($cmd, $ncmd).\n";
|
||||
$ncmd++;
|
||||
}
|
||||
|
||||
for my $func (@$mappings) {
|
||||
next unless $func->{has_get};
|
||||
my $name = $func->{cname};
|
||||
my $cmd = uc $name;
|
||||
my $nargs = 1 + $func->{num_args};
|
||||
print $cfh "#define ESIGAR_$cmd $ncmd\n";
|
||||
print $hfh "-define($cmd, $ncmd).\n";
|
||||
print $hfh "-export([$name/$nargs]).\n";
|
||||
$ncmd++;
|
||||
}
|
||||
|
||||
print $cfh <<EOF;
|
||||
|
||||
static int esigar_dispatch(ErlDrvPort port, sigar_t *sigar, int cmd, char *bytes) {
|
||||
switch (cmd) {
|
||||
EOF
|
||||
for my $func (@$mappings) {
|
||||
next unless $func->{has_get};
|
||||
my $name = $func->{cname};
|
||||
my $cmd = uc $name;
|
||||
my $arg = "";
|
||||
if ($func->{num_args}) {
|
||||
$arg = ", Arg";
|
||||
}
|
||||
|
||||
print $gfh <<EOF;
|
||||
$name({sigar, S}$arg) ->
|
||||
do_command(S, ?$cmd$arg).
|
||||
|
||||
EOF
|
||||
print $cfh <<EOF
|
||||
case ESIGAR_$cmd:
|
||||
return e$func->{sigar_function}(port, sigar, bytes);
|
||||
EOF
|
||||
}
|
||||
print $cfh <<EOF;
|
||||
default:
|
||||
esigar_notimpl(port, sigar, cmd);
|
||||
return SIGAR_ENOTIMPL;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
$self->SUPER::finish;
|
||||
}
|
||||
|
||||
#XXX not currently supporting netware
|
||||
package SigarWrapper::Netware;
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
all:
|
||||
perl -Mlib=.. -MSigarWrapper -e generate Erlang .
|
||||
cd src && make
|
||||
cd c_src && make
|
||||
|
||||
shell:
|
||||
make all
|
||||
erl -pa ebin
|
||||
|
||||
clean:
|
||||
cd src && make clean
|
||||
cd c_src && make clean
|
|
@ -0,0 +1,40 @@
|
|||
## SIGAR driver for Erlang
|
||||
|
||||
If you're not already familar with sigar, have a look at the [SIGAR Wiki](http://sigar.hyperic.com).
|
||||
|
||||
Also helpful: **../../include/sigar.h**, **../*/examples** and
|
||||
**../java/src/org/hyperic/sigar/cmd/** to get an idea of what you can do.
|
||||
|
||||
### Building
|
||||
|
||||
The other bindings/* inline the libsigar sources by default, haven't done that yet for erl.
|
||||
So, you'll need a libsigar to link against, one of:
|
||||
|
||||
Ant build:
|
||||
|
||||
cd ../java ; ant
|
||||
ln -s sigar-bin/lib/libsigar-amd64-linux.so sigar-lib/lib/libsigar.so
|
||||
|
||||
Or, download release binary created by the ant build:
|
||||
|
||||
curl -o priv/libsigar.so http://svn.hyperic.org/projects/sigar_bin/dist/SIGAR_1_6_2/lib/libsigar-amd64-linux.so
|
||||
|
||||
Or, top-level autotools build (WIP):
|
||||
|
||||
cd ../.. ; ./autogen.sh && ./configure && make install
|
||||
|
||||
Once you have a libsigar in place, just run **make** and have a look at the **examples/**.
|
||||
|
||||
Note that the majority of the driver code is generated by **../SigarWrapper.pm** and output to **priv/gen**.
|
||||
|
||||
### ToDo/Help Wanted
|
||||
|
||||
* Fill out the **examples/** - currently weaksauce in part due to me having just a few hours w/ Erlang
|
||||
|
||||
* Build system - doubt the current will work anywhere cept Linux
|
||||
|
||||
* EUnit
|
||||
|
||||
* Other stuff Erlangers know that I don't
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
GCC = gcc
|
||||
OTP_ROOT = $(shell ./check_otp -root)
|
||||
EI_ROOT = $(shell ./check_otp -ei)
|
||||
EI_LIB = $(EI_ROOT)/lib
|
||||
EI_INC = $(EI_ROOT)/include
|
||||
SIGAR_LIB = ../../java/sigar-bin/lib
|
||||
LDFLAGS = -shared -L${EI_LIB} -lei -lpthread -L${SIGAR_LIB} -L../priv -lsigar
|
||||
SRCS = sigar_drv.c
|
||||
OUTPUT = ../priv/sigar_drv.so
|
||||
CFLAGS = -Wall -fPIC -I../../../include -I${OTP_ROOT}/usr/include -I${EI_INC} -o ${OUTPUT}
|
||||
|
||||
all:
|
||||
${GCC} ${SRCS} ${LDFLAGS} ${CFLAGS}
|
||||
|
||||
clean:
|
||||
rm -rf ${OUTPUT} ../priv/gen/*.c ../priv/gen/*.hrl
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
#copied from jungerl
|
||||
if [ "$1" == "-root" -o "$1" == "" ]; then
|
||||
erl -noinput -eval 'io:format("~s~n", [code:root_dir()]), halt(0).'
|
||||
fi
|
||||
|
||||
if [ "$1" == "-ei" -o "$1" == "" ]; then
|
||||
erl -noinput -eval \
|
||||
'case code:lib_dir("erl_interface") of
|
||||
{error, bad_name} ->
|
||||
io:format("not found~n", []),
|
||||
halt(1);
|
||||
LibDir ->
|
||||
io:format("~s~n", [LibDir]),
|
||||
halt(0)
|
||||
end.'
|
||||
fi
|
|
@ -0,0 +1,394 @@
|
|||
#include <erl_driver.h>
|
||||
#include <ei.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sigar.h"
|
||||
#include "sigar_fileinfo.h"
|
||||
#include "sigar_format.h"
|
||||
#include "sigar_ptql.h"
|
||||
|
||||
typedef struct {
|
||||
ErlDrvPort port;
|
||||
sigar_t *sigar;
|
||||
} sigar_drv_t;
|
||||
|
||||
static ErlDrvData start(ErlDrvPort port, char *cmd) {
|
||||
sigar_drv_t *sd = (sigar_drv_t *)driver_alloc(sizeof(*sd));
|
||||
int status;
|
||||
|
||||
status = sigar_open(&sd->sigar);
|
||||
if (status != SIGAR_OK) {
|
||||
sd->sigar = NULL;
|
||||
driver_failure_posix(port, status);
|
||||
}
|
||||
|
||||
sd->port = port;
|
||||
|
||||
return (ErlDrvData)sd;
|
||||
}
|
||||
|
||||
static void stop(ErlDrvData handle) {
|
||||
sigar_drv_t *driver_data = (sigar_drv_t *)handle;
|
||||
if (driver_data->sigar) {
|
||||
sigar_close(driver_data->sigar);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SIGAR_64BIT
|
||||
#define str2pid(value) strtoull(value, NULL, 10)
|
||||
#else
|
||||
#define str2pid(value) strtoul(value, NULL, 10)
|
||||
#endif
|
||||
|
||||
static sigar_pid_t esigar_pid_get(sigar_t *sigar, char *pid)
|
||||
{
|
||||
if (isdigit(*pid)) {
|
||||
return str2pid(pid);
|
||||
}
|
||||
else if ((*pid == '$') && (*(pid + 1) == '$')) {
|
||||
return sigar_pid_get(sigar);
|
||||
}
|
||||
else {
|
||||
/* XXX cache queries */
|
||||
sigar_ptql_query_t *query;
|
||||
sigar_ptql_error_t error;
|
||||
int status =
|
||||
sigar_ptql_query_create(&query, (char *)pid, &error);
|
||||
|
||||
if (status == SIGAR_OK) {
|
||||
sigar_pid_t qpid;
|
||||
|
||||
status = sigar_ptql_query_find_process(sigar, query, &qpid);
|
||||
sigar_ptql_query_destroy(query);
|
||||
if (status == SIGAR_OK) {
|
||||
return qpid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void esigar_to_strlist(ei_x_buff *x,
|
||||
char **data, unsigned long number)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
ei_x_encode_list_header(x, number);
|
||||
for (i=0; i<number; i++) {
|
||||
ei_x_encode_string(x, data[i]);
|
||||
}
|
||||
ei_x_encode_empty_list(x);
|
||||
}
|
||||
|
||||
typedef void (*esigar_encoder_func_t)(ei_x_buff *x, void *data);
|
||||
|
||||
static void esigar_to_list(ei_x_buff *x,
|
||||
char *data, unsigned long number, int size,
|
||||
esigar_encoder_func_t encoder)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
ei_x_encode_list_header(x, number);
|
||||
for (i=0; i<number; i++, data += size) {
|
||||
encoder(x, data);
|
||||
}
|
||||
ei_x_encode_empty_list(x);
|
||||
}
|
||||
|
||||
#define ESIGAR_NEW(x) \
|
||||
ei_x_new_with_version(x)
|
||||
|
||||
#define ESIGAR_OK(x) \
|
||||
ei_x_encode_tuple_header(x, 2); \
|
||||
ei_x_encode_atom(x, "ok")
|
||||
|
||||
#define ESIGAR_ERROR(x, sigar, status) \
|
||||
ei_x_encode_tuple_header(x, 2); \
|
||||
ei_x_encode_atom(x, "error"); \
|
||||
ei_x_encode_string(x, sigar_strerror(sigar, status))
|
||||
|
||||
#define ESIGAR_SEND(p, x) \
|
||||
driver_output(port, (x)->buff, (x)->index); \
|
||||
ei_x_free(x)
|
||||
|
||||
#define esigar_encode_long(x, k, v) \
|
||||
ei_x_encode_tuple_header(x, 2); \
|
||||
ei_x_encode_atom(x, k); \
|
||||
ei_x_encode_long(x, v)
|
||||
|
||||
#define esigar_encode_ulonglong(x, k, v) \
|
||||
ei_x_encode_tuple_header(x, 2); \
|
||||
ei_x_encode_atom(x, k); \
|
||||
ei_x_encode_ulonglong(x, v)
|
||||
|
||||
#define esigar_encode_char(x, k, v) \
|
||||
ei_x_encode_tuple_header(x, 2); \
|
||||
ei_x_encode_atom(x, k); \
|
||||
ei_x_encode_char(x, v)
|
||||
|
||||
#define esigar_encode_string(x, k, v) \
|
||||
ei_x_encode_tuple_header(x, 2); \
|
||||
ei_x_encode_atom(x, k); \
|
||||
ei_x_encode_string(x, v)
|
||||
|
||||
#define esigar_encode_double(x, k, v) \
|
||||
ei_x_encode_tuple_header(x, 2); \
|
||||
ei_x_encode_atom(x, k); \
|
||||
ei_x_encode_double(x, v)
|
||||
|
||||
static void esigar_encode_net_address(ei_x_buff *x, const char *key,
|
||||
sigar_net_address_t *address)
|
||||
{
|
||||
char buf[SIGAR_INET6_ADDRSTRLEN];
|
||||
sigar_net_address_to_string(NULL, address, buf);
|
||||
esigar_encode_string(x, key, buf);
|
||||
}
|
||||
|
||||
#define esigar_encode_netaddr(x, k, v) \
|
||||
esigar_encode_net_address(x, k, &v)
|
||||
|
||||
static void esigar_notimpl(ErlDrvPort port, sigar_t *sigar, int cmd)
|
||||
{
|
||||
ei_x_buff x;
|
||||
|
||||
ESIGAR_NEW(&x);
|
||||
ESIGAR_ERROR(&x, sigar, SIGAR_ENOTIMPL);
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
#include "../priv/gen/sigar_drv_gen.c"
|
||||
|
||||
static void esigar_loadavg_get(ErlDrvPort port, sigar_t *sigar)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
sigar_loadavg_t loadavg;
|
||||
|
||||
ESIGAR_NEW(&x);
|
||||
|
||||
if ((status = sigar_loadavg_get(sigar, &loadavg)) == SIGAR_OK) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
ei_x_encode_list_header(&x, 3);
|
||||
ei_x_encode_double(&x, loadavg.loadavg[0]);
|
||||
ei_x_encode_double(&x, loadavg.loadavg[1]);
|
||||
ei_x_encode_double(&x, loadavg.loadavg[2]);
|
||||
ei_x_encode_empty_list(&x);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
static void esigar_net_connection_list_get(ErlDrvPort port, sigar_t *sigar,
|
||||
unsigned int flags)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
sigar_net_connection_list_t list;
|
||||
|
||||
ei_x_new_with_version(&x);
|
||||
|
||||
if ((status = sigar_net_connection_list_get(sigar, &list, flags) == SIGAR_OK)) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
esigar_to_list(&x,
|
||||
(char *)&list.data[0], list.number,
|
||||
sizeof(*list.data),
|
||||
(esigar_encoder_func_t)esigar_encode_net_connection);
|
||||
|
||||
sigar_net_connection_list_destroy(sigar, &list);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
static void esigar_net_interface_list_get(ErlDrvPort port, sigar_t *sigar)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
sigar_net_interface_list_t list;
|
||||
|
||||
ei_x_new_with_version(&x);
|
||||
|
||||
if ((status = sigar_net_interface_list_get(sigar, &list) == SIGAR_OK)) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
esigar_to_strlist(&x, list.data, list.number);
|
||||
sigar_net_interface_list_destroy(sigar, &list);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
static void esigar_file_system_list_get(ErlDrvPort port, sigar_t *sigar)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
sigar_file_system_list_t list;
|
||||
|
||||
ei_x_new_with_version(&x);
|
||||
|
||||
if ((status = sigar_file_system_list_get(sigar, &list) == SIGAR_OK)) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
esigar_to_list(&x,
|
||||
(char *)&list.data[0], list.number,
|
||||
sizeof(*list.data),
|
||||
(esigar_encoder_func_t)esigar_encode_file_system);
|
||||
|
||||
sigar_file_system_list_destroy(sigar, &list);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
static void esigar_net_route_list_get(ErlDrvPort port, sigar_t *sigar)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
sigar_net_route_list_t list;
|
||||
|
||||
ei_x_new_with_version(&x);
|
||||
|
||||
if ((status = sigar_net_route_list_get(sigar, &list) == SIGAR_OK)) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
esigar_to_list(&x,
|
||||
(char *)&list.data[0], list.number,
|
||||
sizeof(*list.data),
|
||||
(esigar_encoder_func_t)esigar_encode_net_route);
|
||||
|
||||
sigar_net_route_list_destroy(sigar, &list);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
static void esigar_cpu_info_list_get(ErlDrvPort port, sigar_t *sigar)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
sigar_cpu_info_list_t list;
|
||||
|
||||
ei_x_new_with_version(&x);
|
||||
|
||||
if ((status = sigar_cpu_info_list_get(sigar, &list) == SIGAR_OK)) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
esigar_to_list(&x,
|
||||
(char *)&list.data[0], list.number,
|
||||
sizeof(*list.data),
|
||||
(esigar_encoder_func_t)esigar_encode_cpu_info);
|
||||
|
||||
sigar_cpu_info_list_destroy(sigar, &list);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
static void esigar_who_list_get(ErlDrvPort port, sigar_t *sigar)
|
||||
{
|
||||
int status;
|
||||
ei_x_buff x;
|
||||
sigar_who_list_t list;
|
||||
|
||||
ei_x_new_with_version(&x);
|
||||
|
||||
if ((status = sigar_who_list_get(sigar, &list) == SIGAR_OK)) {
|
||||
ESIGAR_OK(&x);
|
||||
|
||||
esigar_to_list(&x,
|
||||
(char *)&list.data[0], list.number,
|
||||
sizeof(*list.data),
|
||||
(esigar_encoder_func_t)esigar_encode_who);
|
||||
|
||||
sigar_who_list_destroy(sigar, &list);
|
||||
}
|
||||
else {
|
||||
ESIGAR_ERROR(&x, sigar, status);
|
||||
}
|
||||
|
||||
ESIGAR_SEND(port, &x);
|
||||
}
|
||||
|
||||
static void outputv(ErlDrvData handle, ErlIOVec *ev) {
|
||||
sigar_drv_t *sd = (sigar_drv_t *)handle;
|
||||
sigar_t *sigar = sd->sigar;
|
||||
ErlDrvPort port = sd->port;
|
||||
ErlDrvBinary *data = ev->binv[1];
|
||||
int cmd = data->orig_bytes[0];
|
||||
|
||||
switch(cmd) {
|
||||
case ESIGAR_NET_CONNECTION_LIST:
|
||||
esigar_net_connection_list_get(port, sigar,
|
||||
data->orig_bytes[1]);
|
||||
break;
|
||||
case ESIGAR_NET_INTERFACE_LIST:
|
||||
esigar_net_interface_list_get(port, sigar);
|
||||
break;
|
||||
case ESIGAR_NET_ROUTE_LIST:
|
||||
esigar_net_route_list_get(port, sigar);
|
||||
break;
|
||||
case ESIGAR_FILE_SYSTEM_LIST:
|
||||
esigar_file_system_list_get(port, sigar);
|
||||
break;
|
||||
case ESIGAR_CPU_INFO_LIST:
|
||||
esigar_cpu_info_list_get(port, sigar);
|
||||
break;
|
||||
case ESIGAR_WHO_LIST:
|
||||
esigar_who_list_get(port, sigar);
|
||||
break;
|
||||
case ESIGAR_LOADAVG:
|
||||
esigar_loadavg_get(port, sigar);
|
||||
break;
|
||||
default:
|
||||
esigar_dispatch(port, sigar, cmd, &data->orig_bytes[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ErlDrvEntry sigar_driver_entry = {
|
||||
NULL, /* init */
|
||||
start, /* startup */
|
||||
stop, /* shutdown */
|
||||
NULL, /* output */
|
||||
NULL, /* ready_input */
|
||||
NULL, /* ready_output */
|
||||
"sigar_drv", /* name of the driver */
|
||||
NULL, /* finish */
|
||||
NULL, /* handle */
|
||||
NULL, /* control */
|
||||
NULL, /* timeout */
|
||||
outputv, /* outputv */
|
||||
NULL, /* ready_async */
|
||||
NULL, /* flush */
|
||||
NULL, /* call */
|
||||
NULL, /* event */
|
||||
ERL_DRV_EXTENDED_MARKER, /* ERL_DRV_EXTENDED_MARKER */
|
||||
ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MAJOR_VERSION */
|
||||
ERL_DRV_EXTENDED_MAJOR_VERSION, /* ERL_DRV_EXTENDED_MINOR_VERSION */
|
||||
ERL_DRV_FLAG_USE_PORT_LOCKING /* ERL_DRV_FLAGs */
|
||||
};
|
||||
|
||||
DRIVER_INIT(sigar_driver) {
|
||||
return &sigar_driver_entry;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
*.beam
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env escript
|
||||
|
||||
-include(sigar).
|
||||
|
||||
main(_) ->
|
||||
{ok, S} = sigar:start(),
|
||||
{ok, FsList} = sigar:file_system_list(S),
|
||||
lists:map(
|
||||
fun(Fs) ->
|
||||
io:format("~s ~n", [sigar:get_value(dir_name, Fs)]) end,
|
||||
FsList),
|
||||
sigar:stop(S).
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env escript
|
||||
|
||||
-include(sigar).
|
||||
|
||||
main(_) ->
|
||||
{ok, S} = sigar:start(),
|
||||
{ok, Mem} = sigar:mem(S),
|
||||
io:format("\tTotal\tUsed\tFree~n"),
|
||||
io:format("Mem: "),
|
||||
lists:map(
|
||||
fun(K) ->
|
||||
io:format("~w\t", [sigar:get_value(K, Mem)/1024]) end,
|
||||
[total, used, free]),
|
||||
io:format("~n"),
|
||||
{ok, Swap} = sigar:swap(S),
|
||||
io:format("Swap: "),
|
||||
lists:map(
|
||||
fun(K) ->
|
||||
io:format("~w\t", [sigar:get_value(K, Swap)/1024]) end,
|
||||
[total, used, free]),
|
||||
io:format("~n"),
|
||||
io:format("RAM: ~wMB~n", [sigar:get_value(ram, Mem)]),
|
||||
sigar:stop(S).
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env escript
|
||||
|
||||
-include(sigar).
|
||||
|
||||
main(_) ->
|
||||
{ok, S} = sigar:start(),
|
||||
{ok, Names} = sigar:net_interface_list(S),
|
||||
lists:map(
|
||||
fun(K) ->
|
||||
{ok, Ifconfig} = sigar:net_interface_config(S, K),
|
||||
io:format("~s ~s~n", [K, sigar:get_value(address, Ifconfig)]) end,
|
||||
Names),
|
||||
sigar:stop(S).
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env escript
|
||||
|
||||
-include(sigar).
|
||||
|
||||
main(_) ->
|
||||
{ok, S} = sigar:start(),
|
||||
{ok, Mem} = sigar:proc_mem(S, "$$"),
|
||||
io:format("Size\tResident~n"),
|
||||
lists:map(
|
||||
fun(K) ->
|
||||
io:format("~w\t", [sigar:get_value(K, Mem)/1024]) end,
|
||||
[size, resident]),
|
||||
io:format("~n"),
|
||||
sigar:stop(S).
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env escript
|
||||
|
||||
-include(sigar).
|
||||
|
||||
main(_) ->
|
||||
{ok, S} = sigar:start(),
|
||||
case sigar:loadavg(S) of
|
||||
{ok, Avg} ->
|
||||
lists:map(
|
||||
fun(A) ->
|
||||
io:format("~w% ", [A]) end,
|
||||
Avg);
|
||||
{error, Err} ->
|
||||
Err
|
||||
end,
|
||||
io:format("~n"),
|
||||
sigar:stop(S).
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env escript
|
||||
|
||||
-include(sigar).
|
||||
|
||||
main(_) ->
|
||||
{ok, S} = sigar:start(),
|
||||
{ok, List} = sigar:who_list(S),
|
||||
lists:map(
|
||||
fun(Who) ->
|
||||
lists:map(
|
||||
fun(K) ->
|
||||
io:format("~s\t", [sigar:get_value(K, Who)]) end,
|
||||
[user, device, host]),
|
||||
io:format("~n")
|
||||
end, List),
|
||||
sigar:stop(S).
|
|
@ -0,0 +1 @@
|
|||
*.so
|
|
@ -0,0 +1,2 @@
|
|||
*.c
|
||||
*.hrl
|
|
@ -0,0 +1,11 @@
|
|||
ERLC=erlc
|
||||
EBIN=../ebin
|
||||
INCLUDE=../include
|
||||
EFLAGS=-I ${INCLUDE} -o ${EBIN}
|
||||
SRCS=`ls *.erl`
|
||||
|
||||
all:
|
||||
${ERLC} ${EFLAGS} ${SRCS}
|
||||
|
||||
clean:
|
||||
rm -rf ${EBIN}/*.beam
|
|
@ -0,0 +1,87 @@
|
|||
-module(sigar).
|
||||
|
||||
% generated by SigarWrapper.pm
|
||||
-include("../priv/gen/sigar.hrl").
|
||||
|
||||
-export([start/0, stop/1, get_value/2]).
|
||||
|
||||
% handrolled wrappers
|
||||
-export([loadavg/1,
|
||||
net_connection_list/2,
|
||||
net_interface_list/1,
|
||||
net_route_list/1,
|
||||
file_system_list/1,
|
||||
cpu_info_list/1,
|
||||
who_list/1]).
|
||||
|
||||
-define(NETCONN_CLIENT, 0x01).
|
||||
-define(NETCONN_SERVER, 0x02).
|
||||
|
||||
-define(SIGAR_NETCONN_TCP, 0x10).
|
||||
-define(SIGAR_NETCONN_UDP, 0x20).
|
||||
-define(SIGAR_NETCONN_RAW, 0x40).
|
||||
-define(SIGAR_NETCONN_UNIX, 0x80).
|
||||
|
||||
start() ->
|
||||
case load_driver() of
|
||||
ok ->
|
||||
S = open_port({spawn, 'sigar_drv'}, [binary]),
|
||||
{ok, {sigar, S}};
|
||||
{error, Err} ->
|
||||
Msg = erl_ddll:format_error(Err),
|
||||
{error, Msg}
|
||||
end.
|
||||
|
||||
% handrolled wrappers
|
||||
loadavg({sigar, S}) ->
|
||||
do_command(S, ?LOADAVG).
|
||||
|
||||
net_connection_list({sigar, S}, F) ->
|
||||
do_command(S, ?NET_CONNECTION_LIST, F).
|
||||
|
||||
net_interface_list({sigar, S}) ->
|
||||
do_command(S, ?NET_INTERFACE_LIST).
|
||||
|
||||
net_route_list({sigar, S}) ->
|
||||
do_command(S, ?NET_ROUTE_LIST).
|
||||
|
||||
file_system_list({sigar, S}) ->
|
||||
do_command(S, ?FILE_SYSTEM_LIST).
|
||||
|
||||
cpu_info_list({sigar, S}) ->
|
||||
do_command(S, ?CPU_INFO_LIST).
|
||||
|
||||
who_list({sigar, S}) ->
|
||||
do_command(S, ?WHO_LIST).
|
||||
|
||||
% generated by SigarWrapper.pm
|
||||
-include("../priv/gen/sigar_gen.hrl").
|
||||
|
||||
% XXX must be a better way
|
||||
get_value(Key, List) ->
|
||||
case lists:keysearch(Key,1,List) of
|
||||
false ->
|
||||
1;
|
||||
{ value, {Key, N} } ->
|
||||
N
|
||||
end.
|
||||
|
||||
stop({sigar, S}) ->
|
||||
unlink(S),
|
||||
port_close(S).
|
||||
|
||||
load_driver() ->
|
||||
Dir = filename:join([filename:dirname(code:which(sigar)), "..", "priv"]),
|
||||
erl_ddll:load(Dir, "sigar_drv").
|
||||
|
||||
do_command(S, C) ->
|
||||
port_command(S, [C]),
|
||||
receive
|
||||
{S, {data, Bin}} -> binary_to_term(Bin)
|
||||
end.
|
||||
|
||||
do_command(S, C, A) ->
|
||||
port_command(S, [C, A]),
|
||||
receive
|
||||
{S, {data, Bin}} -> binary_to_term(Bin)
|
||||
end.
|
Loading…
Reference in New Issue