From 22c0d9e356eeefca13a646796270ddf33a2d12fc Mon Sep 17 00:00:00 2001 From: Doug MacEachern Date: Sun, 14 Jun 2009 21:29:08 -0700 Subject: [PATCH] experimental erlang driver --- bindings/SigarWrapper.pm | 173 ++++++++++++- bindings/erl/Makefile | 12 + bindings/erl/README.markdown | 40 +++ bindings/erl/c_src/Makefile | 16 ++ bindings/erl/c_src/check_otp | 17 ++ bindings/erl/c_src/sigar_drv.c | 394 +++++++++++++++++++++++++++++ bindings/erl/ebin/.gitignore | 1 + bindings/erl/examples/df.erl | 14 + bindings/erl/examples/free.erl | 25 ++ bindings/erl/examples/ifconfig.erl | 15 ++ bindings/erl/examples/ps.erl | 16 ++ bindings/erl/examples/uptime.erl | 19 ++ bindings/erl/examples/who.erl | 16 ++ bindings/erl/priv/.gitignore | 1 + bindings/erl/priv/gen/.gitignore | 2 + bindings/erl/src/Makefile | 11 + bindings/erl/src/sigar.erl | 87 +++++++ 17 files changed, 858 insertions(+), 1 deletion(-) create mode 100644 bindings/erl/Makefile create mode 100644 bindings/erl/README.markdown create mode 100644 bindings/erl/c_src/Makefile create mode 100755 bindings/erl/c_src/check_otp create mode 100644 bindings/erl/c_src/sigar_drv.c create mode 100644 bindings/erl/ebin/.gitignore create mode 100755 bindings/erl/examples/df.erl create mode 100755 bindings/erl/examples/free.erl create mode 100755 bindings/erl/examples/ifconfig.erl create mode 100755 bindings/erl/examples/ps.erl create mode 100755 bindings/erl/examples/uptime.erl create mode 100755 bindings/erl/examples/who.erl create mode 100644 bindings/erl/priv/.gitignore create mode 100644 bindings/erl/priv/gen/.gitignore create mode 100644 bindings/erl/src/Makefile create mode 100644 bindings/erl/src/sigar.erl diff --git a/bindings/SigarWrapper.pm b/bindings/SigarWrapper.pm index dcc3f19a..f0c2de88 100644 --- a/bindings/SigarWrapper.pm +++ b/bindings/SigarWrapper.pm @@ -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 <{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 <{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 <{has_get}; + my $name = $func->{cname}; + my $cmd = uc $name; + my $arg = ""; + if ($func->{num_args}) { + $arg = ", Arg"; + } + + print $gfh < + do_command(S, ?$cmd$arg). + +EOF + print $cfh <{sigar_function}(port, sigar, bytes); +EOF + } + print $cfh <SUPER::finish; +} + #XXX not currently supporting netware package SigarWrapper::Netware; diff --git a/bindings/erl/Makefile b/bindings/erl/Makefile new file mode 100644 index 00000000..d8614fbb --- /dev/null +++ b/bindings/erl/Makefile @@ -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 diff --git a/bindings/erl/README.markdown b/bindings/erl/README.markdown new file mode 100644 index 00000000..7689b981 --- /dev/null +++ b/bindings/erl/README.markdown @@ -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 + + diff --git a/bindings/erl/c_src/Makefile b/bindings/erl/c_src/Makefile new file mode 100644 index 00000000..776085c0 --- /dev/null +++ b/bindings/erl/c_src/Makefile @@ -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 diff --git a/bindings/erl/c_src/check_otp b/bindings/erl/c_src/check_otp new file mode 100755 index 00000000..ebb1a178 --- /dev/null +++ b/bindings/erl/c_src/check_otp @@ -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 diff --git a/bindings/erl/c_src/sigar_drv.c b/bindings/erl/c_src/sigar_drv.c new file mode 100644 index 00000000..c125dbd4 --- /dev/null +++ b/bindings/erl/c_src/sigar_drv.c @@ -0,0 +1,394 @@ +#include +#include +#include +#include + +#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; ibuff, (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; +} diff --git a/bindings/erl/ebin/.gitignore b/bindings/erl/ebin/.gitignore new file mode 100644 index 00000000..17278c08 --- /dev/null +++ b/bindings/erl/ebin/.gitignore @@ -0,0 +1 @@ +*.beam diff --git a/bindings/erl/examples/df.erl b/bindings/erl/examples/df.erl new file mode 100755 index 00000000..7ac0fa05 --- /dev/null +++ b/bindings/erl/examples/df.erl @@ -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). + + diff --git a/bindings/erl/examples/free.erl b/bindings/erl/examples/free.erl new file mode 100755 index 00000000..d60967ab --- /dev/null +++ b/bindings/erl/examples/free.erl @@ -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). + + diff --git a/bindings/erl/examples/ifconfig.erl b/bindings/erl/examples/ifconfig.erl new file mode 100755 index 00000000..e5d5aa54 --- /dev/null +++ b/bindings/erl/examples/ifconfig.erl @@ -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). + + diff --git a/bindings/erl/examples/ps.erl b/bindings/erl/examples/ps.erl new file mode 100755 index 00000000..4a43b751 --- /dev/null +++ b/bindings/erl/examples/ps.erl @@ -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). + + diff --git a/bindings/erl/examples/uptime.erl b/bindings/erl/examples/uptime.erl new file mode 100755 index 00000000..09166422 --- /dev/null +++ b/bindings/erl/examples/uptime.erl @@ -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). + + diff --git a/bindings/erl/examples/who.erl b/bindings/erl/examples/who.erl new file mode 100755 index 00000000..be1a8122 --- /dev/null +++ b/bindings/erl/examples/who.erl @@ -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). diff --git a/bindings/erl/priv/.gitignore b/bindings/erl/priv/.gitignore new file mode 100644 index 00000000..140f8cf8 --- /dev/null +++ b/bindings/erl/priv/.gitignore @@ -0,0 +1 @@ +*.so diff --git a/bindings/erl/priv/gen/.gitignore b/bindings/erl/priv/gen/.gitignore new file mode 100644 index 00000000..7d6b49ed --- /dev/null +++ b/bindings/erl/priv/gen/.gitignore @@ -0,0 +1,2 @@ +*.c +*.hrl \ No newline at end of file diff --git a/bindings/erl/src/Makefile b/bindings/erl/src/Makefile new file mode 100644 index 00000000..8787cfeb --- /dev/null +++ b/bindings/erl/src/Makefile @@ -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 diff --git a/bindings/erl/src/sigar.erl b/bindings/erl/src/sigar.erl new file mode 100644 index 00000000..6e4e4974 --- /dev/null +++ b/bindings/erl/src/sigar.erl @@ -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.