File OpenIPMI_2.0.21_to_HEAD.patch of Package OpenIPMI.8463
diff --git a/doc/IPMI.ltx b/doc/IPMI.ltx
index 35774ac..9d741c9 100644
--- a/doc/IPMI.ltx
+++ b/doc/IPMI.ltx
@@ -5896,7 +5896,7 @@ iterator function with a callback function:
\begin{verbatim}
static void
-handle_entity(ipmi_domain_t *domain, ipmi_entity_t *entity, void *cb_data)
+handle_entity(ipmi_entity_t *entity, void *cb_data)
{
my_data_t *my_data = cb_data;
/* Process the entity here */
diff --git a/glib/glib_os_hnd.c b/glib/glib_os_hnd.c
index cf21c27..868e96c 100644
--- a/glib/glib_os_hnd.c
+++ b/glib/glib_os_hnd.c
@@ -772,6 +772,31 @@ static void sset_log_handler(os_handler_t *handler,
info->log_handler = log_handler;
}
+static int get_glib_monotonic_time(os_handler_t *handler,
+ struct timeval *tv)
+{
+ gint64 now;
+
+ now = g_get_monotonic_time();
+ tv->tv_sec = now / G_TIME_SPAN_SECOND;
+ tv->tv_usec = now % G_TIME_SPAN_SECOND;
+ return 0;
+}
+
+static int get_glib_time(os_handler_t *handler,
+ struct timeval *tv)
+{
+ GDateTime *now;
+ GTimeVal gtv;
+
+ now = g_date_time_new_now_utc();
+ g_date_time_to_timeval(now, >v);
+ g_date_time_unref(now);
+ tv->tv_sec = gtv.tv_sec;
+ tv->tv_usec = gtv.tv_usec;
+ return 0;
+}
+
static os_handler_t ipmi_glib_os_handler =
{
.mem_alloc = glib_malloc,
@@ -818,6 +843,8 @@ static os_handler_t ipmi_glib_os_handler =
.database_set_filename = set_gdbm_filename,
#endif
.set_log_handler = sset_log_handler,
+ .get_monotonic_time = get_glib_monotonic_time,
+ .get_real_time = get_glib_time
};
diff --git a/include/OpenIPMI/ipmiif.h.in b/include/OpenIPMI/ipmiif.h.in
index 22b2e22..9cdbf34 100644
--- a/include/OpenIPMI/ipmiif.h.in
+++ b/include/OpenIPMI/ipmiif.h.in
@@ -480,6 +480,11 @@ int ipmi_domain_store_entities(ipmi_domain_t *domain,
/* Returns if the domain thinks it has a connection up. */
int ipmi_domain_con_up(ipmi_domain_t *domain);
+/*
+ * Returns true if the domain has finished coming up, false if not.
+ */
+int ipmi_domain_is_fully_up(ipmi_domain_t *domain);
+
/* Iterate through the connections on a domain. */
typedef void (*ipmi_connection_ptr_cb)(ipmi_domain_t *domain, int conn,
void *cb_data);
diff --git a/ipmi_sim_lancontrol b/ipmi_sim_lancontrol
new file mode 100755
index 0000000..be79f7a
--- /dev/null
+++ b/ipmi_sim_lancontrol
@@ -0,0 +1,72 @@
+#! /bin/sh
+# ipmi_sim_lancontrol - provide link addresses to ipmi_sim for device $1
+# See lan_config_program in ipmi_lan(5)
+#
+# 2015-05-06 Noel Burton-Krahn <noel@pistoncloud.com>
+
+set -eu
+
+# arguments: dev op var
+# network interface
+dev=$1
+# get or set. This script just supports get
+op=$2
+# var name
+var=$3
+
+# my default gateway device
+gw_dev=$(ip route | sed -ne 's/default via [.0-9]* dev \([^ ]*\) .*/\1/p')
+
+link_ip() {
+ ip -o -4 addr list $1 | sed -ne 's/.* inet \([.0-9]*\)\/.*/\1/p'
+}
+
+link_mac() {
+ ip -o link list $1 | sed -ne 's/.* link\/ether \([:0-9a-f]*\) .*/\1/p'
+}
+
+link_subnet() {
+ ifconfig $1 | sed -n -e 's/.*Mask:\([.0-9]*\).*/\1/p'
+}
+
+get_val() {
+ case $var in
+ ip_addr_src)
+ echo "dhcp"
+ ;;
+
+ ip_addr)
+ link_ip $dev
+ ;;
+
+ mac_addr)
+ link_mac $dev
+ ;;
+
+ subnet_mask)
+ link_subnet $dev
+ ;;
+
+ default_gw_ip_addr)
+ link_ip $gw_dev
+ ;;
+
+ default_gw_mac_addr)
+ link_mac $gw_dev
+ ;;
+
+ backup_gw_ip_addr)
+ link_ip $gw_dev
+ ;;
+
+ backup_gw_mac_addr)
+ link_mac $gw_dev
+ ;;
+ esac
+}
+
+if [ $op = "get" ]; then
+ val=$(get_val $var)
+ echo "$var: $val"
+fi
+
diff --git a/lanserv/OpenIPMI/extcmd.h b/lanserv/OpenIPMI/extcmd.h
index 167090a..382aca2 100644
--- a/lanserv/OpenIPMI/extcmd.h
+++ b/lanserv/OpenIPMI/extcmd.h
@@ -64,6 +64,7 @@ enum extcmd_info_type_e {
extcmd_mac,
extcmd_uchar,
extcmd_int,
+ extcmd_ident,
};
typedef struct extcmd_map_s {
diff --git a/lanserv/OpenIPMI/mcserv.h b/lanserv/OpenIPMI/mcserv.h
index 032ac28..e0ca58a 100644
--- a/lanserv/OpenIPMI/mcserv.h
+++ b/lanserv/OpenIPMI/mcserv.h
@@ -266,7 +266,8 @@ int ipmi_mc_add_sensor(lmc_data_t *mc,
unsigned char lun,
unsigned char sens_num,
unsigned char type,
- unsigned char event_reading_code);
+ unsigned char event_reading_code,
+ int event_only);
int ipmi_mc_add_polled_sensor(lmc_data_t *mc,
unsigned char lun,
@@ -368,6 +369,7 @@ int ipmi_mc_set_frudata_handler(lmc_data_t *mc, unsigned int fru,
#define CHASSIS_CONTROL_BOOT 2
#define CHASSIS_CONTROL_BOOT_INFO_ACK 3
#define CHASSIS_CONTROL_GRACEFUL_SHUTDOWN 4
+#define CHASSIS_CONTROL_IDENTIFY 5
void ipmi_mc_set_chassis_control_func(lmc_data_t *mc,
int (*set)(lmc_data_t *mc, int op,
unsigned char *val,
diff --git a/lanserv/OpenIPMI/serv.h b/lanserv/OpenIPMI/serv.h
index b954af3..c439a0e 100644
--- a/lanserv/OpenIPMI/serv.h
+++ b/lanserv/OpenIPMI/serv.h
@@ -179,7 +179,9 @@ struct channel_s
#define HW_OP_SEND_NMI 3
#define HW_OP_IRQ_ENABLE 4
#define HW_OP_IRQ_DISABLE 5
-#define HW_OP_GRACEFUL_SHUTDOWN 5
+#define HW_OP_GRACEFUL_SHUTDOWN 6
+#define HW_OP_CHECK_POWER 7
+#define HW_OP_FORCEOFF 8
unsigned int hw_capabilities; /* Bitmask of above bits for capabilities. */
#define HW_OP_CAN_RESET(chan) ((chan)->hw_capabilities & (1 << HW_OP_RESET))
#define HW_OP_CAN_POWER(chan) ((chan)->hw_capabilities & (1 << HW_OP_POWERON))
@@ -187,7 +189,7 @@ struct channel_s
#define HW_OP_CAN_IRQ(chan) ((chan)->hw_capabilities & (1 << HW_OP_IRQ_ENABLE))
#define HW_OP_CAN_GRACEFUL_SHUTDOWN(chan) ((chan)->hw_capabilities & \
(1 << HW_OP_GRACEFUL_SHUTDOWN))
- void (*hw_op)(channel_t *chan, unsigned int op);
+ int (*hw_op)(channel_t *chan, unsigned int op);
/* Special command handlers. */
void (*set_lan_parms)(channel_t *chan, msg_t *msg, unsigned char *rdata,
diff --git a/lanserv/bmc.c b/lanserv/bmc.c
index 8af103c..32eed36 100644
--- a/lanserv/bmc.c
+++ b/lanserv/bmc.c
@@ -625,9 +625,14 @@ ipmi_mc_start_cmd(lmc_data_t *mc)
return;
}
- if (mc->startcmd.vmpid)
+ if (mc->startcmd.vmpid) {
/* Already running */
+
+ /* If we are waiting for a poweroff, disable that. */
+ if (mc->startcmd.wait_poweroff)
+ mc->startcmd.wait_poweroff = 0;
return;
+ }
ipmi_do_start_cmd(&mc->startcmd);
}
@@ -641,8 +646,8 @@ chan_start_cmd(channel_t *chan)
static void
ipmi_mc_stop_cmd(lmc_data_t *mc, int do_it_now)
{
- if (mc->startcmd.wait_poweroff)
- /* Already powering off. */
+ if (mc->startcmd.wait_poweroff || !mc->startcmd.vmpid)
+ /* Already powering/powered off. */
return;
if (!do_it_now)
mc->startcmd.wait_poweroff = mc->startcmd.poweroff_wait_time;
@@ -780,18 +785,19 @@ handle_tick(void *info, unsigned int seconds)
lmc_data_t *mc = info;
if (mc->startcmd.wait_poweroff) {
- if (mc->startcmd.vmpid == 0) {
- mc->startcmd.wait_poweroff = 0;
- } else if (mc->startcmd.wait_poweroff > 0) {
+ if (mc->startcmd.wait_poweroff > 0) {
/* Waiting for the first kill */
mc->startcmd.wait_poweroff--;
if (mc->startcmd.wait_poweroff == 0) {
- ipmi_do_kill(&mc->startcmd, 0);
+ if (HW_OP_CAN_POWER(mc->channels[15]))
+ mc->channels[15]->hw_op(mc->channels[15], HW_OP_FORCEOFF);
+ else if (mc->startcmd.vmpid)
+ ipmi_do_kill(&mc->startcmd, 0);
mc->startcmd.wait_poweroff = -mc->startcmd.kill_wait_time;
}
} else {
mc->startcmd.wait_poweroff++;
- if (mc->startcmd.wait_poweroff == 0)
+ if (mc->startcmd.wait_poweroff == 0 && mc->startcmd.vmpid)
ipmi_do_kill(&mc->startcmd, 1);
}
}
diff --git a/lanserv/bmc.h b/lanserv/bmc.h
index cea8c1a..10cc773 100644
--- a/lanserv/bmc.h
+++ b/lanserv/bmc.h
@@ -135,6 +135,8 @@ struct sensor_s
uint16_t threshold_supported; /* Bitmask */
unsigned char thresholds[6];
+ int event_only;
+
unsigned char event_support;
/* 0 for assertion, 1 for deassertion. */
diff --git a/lanserv/bmc_app.c b/lanserv/bmc_app.c
index 38fd619..9a0d482 100644
--- a/lanserv/bmc_app.c
+++ b/lanserv/bmc_app.c
@@ -171,6 +171,12 @@ watchdog_timeout(void *cb_data)
if (!mc->watchdog_running)
goto out;
+ if( !sens ) {
+ // NOTE(noelbk): The watchdog sensor should have been defined
+ // earlier, but don't SEGFAULT if it isn't
+ goto out;
+ }
+
if (! mc->watchdog_preaction_ran) {
struct timeval tv, now;
@@ -224,7 +230,7 @@ watchdog_timeout(void *cb_data)
break;
case IPMI_MC_WATCHDOG_ACTION_POWER_CYCLE:
- set_sensor_bit(mc, sens, 2, 1, 0xc3, mc->watchdog_use & 0xf, 0xff, 1);
+ set_sensor_bit(mc, sens, 3, 1, 0xc3, mc->watchdog_use & 0xf, 0xff, 1);
bchan->hw_op(bchan, HW_OP_POWEROFF);
start_poweron_timer(mc);
break;
@@ -368,6 +374,8 @@ handle_reset_watchdog_timer(lmc_data_t *mc,
}
do_watchdog_reset(mc);
+ rdata[0] = 0x00;
+ *rdata_len = 1;
}
static void
@@ -928,7 +936,7 @@ handle_get_msg(lmc_data_t *mc,
qmsg = mc->recv_q_head;
if (!qmsg) {
rdata[0] = 0x80;
- *rdata_len = 0;
+ *rdata_len = 1;
return;
}
diff --git a/lanserv/bmc_chassis.c b/lanserv/bmc_chassis.c
index 6ca028e..e7231e3 100644
--- a/lanserv/bmc_chassis.c
+++ b/lanserv/bmc_chassis.c
@@ -43,6 +43,8 @@ static extcmd_map_t boot_map[] = {
{ 0, "none" },
{ 1, "pxe" },
{ 2, "default" },
+ { 5, "cdrom" },
+ { 6, "bios" },
{ 0, NULL }
};
@@ -51,7 +53,9 @@ static extcmd_info_t chassis_prog[] = {
{ "power", extcmd_int, NULL, 0 },
{ "reset", extcmd_int, NULL, 0 },
{ "boot", extcmd_uchar, boot_map, 0 },
+ { "boot", extcmd_uchar, boot_map, 0 }, // dup'd for boot info ack
{ "shutdown", extcmd_int, NULL, 0 },
+ { "identify", extcmd_ident, NULL, 0 },
};
static int
@@ -149,8 +153,11 @@ handle_get_chassis_status(lmc_data_t *mc,
return;
}
rdata[1] = val;
- } else {
- rdata[1] = mc->startcmd.vmpid != 0;
+ } else if (mc->startcmd.vmpid) {
+ rdata[1] = 1;
+ } else if (HW_OP_CAN_POWER(mc->channels[15])) {
+ int rv = mc->channels[15]->hw_op(mc->channels[15], HW_OP_CHECK_POWER);
+ rdata[1] = rv > 0;
}
rdata[2] = 0;
rdata[3] = 0;
@@ -277,6 +284,48 @@ handle_chassis_control(lmc_data_t *mc,
}
static void
+handle_chassis_identify(lmc_data_t *mc,
+ msg_t *msg,
+ unsigned char *rdata,
+ unsigned int *rdata_len,
+ void *cb_data)
+{
+ unsigned char val[2];
+
+ rdata[0] = 0;
+ memset(val, 0, sizeof(val));
+
+ if (msg->len == 0)
+ val[0] = 0xf; /* default 15 seconds */
+ else
+ val[0] = msg->data[0]; /* interval */
+
+ if (msg->len > 1) /* force flag is set */
+ val[1] = msg->data[1] & 0x1;
+
+ if (mc->chassis_control_set_func) {
+ int rv;
+ rv = mc->chassis_control_set_func(mc, CHASSIS_CONTROL_IDENTIFY,
+ val, mc->chassis_control_cb_data);
+ if (rv) {
+ rdata[0] = IPMI_UNKNOWN_ERR_CC;
+ *rdata_len = 1;
+ return;
+ }
+ } else if (mc->chassis_control_prog) {
+ if (extcmd_setvals(mc->sysinfo, val, mc->chassis_control_prog,
+ &chassis_prog[CHASSIS_CONTROL_IDENTIFY], NULL, 1)) {
+ rdata[0] = IPMI_UNKNOWN_ERR_CC;
+ *rdata_len = 1;
+ return;
+ }
+ } else {
+ rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
+ *rdata_len = 1;
+ }
+}
+
+static void
set_system_boot_options(lmc_data_t *mc,
msg_t *msg,
unsigned char *rdata,
@@ -326,11 +375,19 @@ set_system_boot_options(lmc_data_t *mc,
rv = mc->chassis_control_set_func(mc, CHASSIS_CONTROL_BOOT_INFO_ACK,
msg->data + 1,
mc->chassis_control_cb_data);
+
if (rv) {
rdata[0] = IPMI_UNKNOWN_ERR_CC;
*rdata_len = 1;
return;
}
+ } else if (mc->chassis_control_prog) {
+ if (extcmd_getvals(mc->sysinfo, &val, mc->chassis_control_prog,
+ &chassis_prog[CHASSIS_CONTROL_BOOT_INFO_ACK], 1)) {
+ rdata[0] = IPMI_UNKNOWN_ERR_CC;
+ *rdata_len = 1;
+ return;
+ }
} else {
rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
*rdata_len = 1;
@@ -459,6 +516,7 @@ cmd_handler_f chassis_netfn_handlers[256] = {
[IPMI_GET_CHASSIS_STATUS_CMD] = handle_get_chassis_status,
[IPMI_CHASSIS_CONTROL_CMD] = handle_chassis_control,
[IPMI_SET_SYSTEM_BOOT_OPTIONS_CMD] = set_system_boot_options,
- [IPMI_GET_SYSTEM_BOOT_OPTIONS_CMD] = get_system_boot_options
+ [IPMI_GET_SYSTEM_BOOT_OPTIONS_CMD] = get_system_boot_options,
+ [IPMI_CHASSIS_IDENTIFY_CMD] = handle_chassis_identify
};
diff --git a/lanserv/bmc_sensor.c b/lanserv/bmc_sensor.c
index bbc00a3..2166dee 100644
--- a/lanserv/bmc_sensor.c
+++ b/lanserv/bmc_sensor.c
@@ -342,7 +342,14 @@ set_sensor_bit(lmc_data_t *mc, sensor_t *sensor, unsigned char bit,
unsigned char evd1, unsigned char evd2, unsigned char evd3,
int gen_event)
{
- if (value != bit_set(sensor->event_status, bit)) {
+ if (sensor->event_only) {
+ if (value)
+ do_event(mc, sensor, gen_event, IPMI_ASSERTION,
+ evd1 | bit, evd2, evd3);
+ else
+ do_event(mc, sensor, gen_event, IPMI_DEASSERTION,
+ evd1 | bit, evd2, evd3);
+ } else if (value != bit_set(sensor->event_status, bit)) {
/* The bit value has changed. */
set_bit(sensor->event_status, bit, value);
if (value && bit_set(sensor->event_enabled[0], bit)) {
@@ -710,6 +717,12 @@ handle_get_sensor_reading(lmc_data_t *mc,
sensor = mc->sensors[msg->rs_lun][sens_num];
+ if (sensor->event_only) {
+ rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
+ *rdata_len = 1;
+ return;
+ }
+
rdata[0] = 0;
rdata[1] = sensor->value;
rdata[2] = ((sensor->events_enabled << 7)
@@ -1109,7 +1122,8 @@ ipmi_mc_add_sensor(lmc_data_t *mc,
unsigned char lun,
unsigned char sens_num,
unsigned char type,
- unsigned char event_reading_code)
+ unsigned char event_reading_code,
+ int event_only)
{
sensor_t *sensor;
lmc_data_t *bmc;
@@ -1127,6 +1141,7 @@ ipmi_mc_add_sensor(lmc_data_t *mc,
sensor->num = sens_num;
sensor->sensor_type = type;
sensor->event_reading_code = event_reading_code;
+ sensor->event_only = event_only;
mc->sensors[lun][sens_num] = sensor;
if (mc->emu->atca_mode && (type == 0xf0)) {
@@ -1531,7 +1546,7 @@ ipmi_mc_add_polled_sensor(lmc_data_t *mc,
sensor_t *sensor;
int err;
- err = ipmi_mc_add_sensor(mc, lun, sens_num, type, event_reading_code);
+ err = ipmi_mc_add_sensor(mc, lun, sens_num, type, event_reading_code, 0);
if (err)
return err;
diff --git a/lanserv/config.c b/lanserv/config.c
index 65b169d..f066396 100644
--- a/lanserv/config.c
+++ b/lanserv/config.c
@@ -831,14 +831,18 @@ read_config(sys_data_t *sys,
} else if (strcmp(tok, "name") == 0) {
err = get_delim_str(&tokptr, &sys->name, &errstr);
} else if (strcmp(tok, "startcmd") == 0) {
- err = get_delim_str(&tokptr, &sys->startcmd->startcmd, &errstr);
+ if (sys->startcmd)
+ err = get_delim_str(&tokptr, &sys->startcmd->startcmd, &errstr);
} else if (strcmp(tok, "startnow") == 0) {
- err = get_bool(&tokptr, &sys->startcmd->startnow, &errstr);
+ if (sys->startcmd)
+ err = get_bool(&tokptr, &sys->startcmd->startnow, &errstr);
} else if (strcmp(tok, "poweroff_wait") == 0) {
- err = get_uint(&tokptr, &sys->startcmd->poweroff_wait_time,
+ if (sys->startcmd)
+ err = get_uint(&tokptr, &sys->startcmd->poweroff_wait_time,
&errstr);
} else if (strcmp(tok, "kill_wait") == 0) {
- err = get_uint(&tokptr, &sys->startcmd->kill_wait_time, &errstr);
+ if (sys->startcmd)
+ err = get_uint(&tokptr, &sys->startcmd->kill_wait_time, &errstr);
} else if (strcmp(tok, "set_working_mc") == 0) {
unsigned char ipmb;
err = get_uchar(&tokptr, &ipmb, &errstr);
diff --git a/lanserv/emu_cmd.c b/lanserv/emu_cmd.c
index 1ec99a1..48fb1dc 100644
--- a/lanserv/emu_cmd.c
+++ b/lanserv/emu_cmd.c
@@ -354,7 +354,12 @@ sensor_add(emu_out_t *out, emu_data_t *emu, lmc_data_t *mc, char **toks)
unsigned char num;
unsigned char type;
unsigned char code;
+ int event_only = 0;
const char *tok;
+ ipmi_sensor_handler_t *handler = NULL;
+ unsigned int poll_rate = 0;
+ void *rcb_data = NULL;
+ const char *errstr;
rv = emu_get_uchar(out, toks, &lun, "LUN", 0);
if (rv)
@@ -377,41 +382,52 @@ sensor_add(emu_out_t *out, emu_data_t *emu, lmc_data_t *mc, char **toks)
* really be part of the main sensor structure.
*/
tok = mystrtok(NULL, " \t\n", toks);
- if (tok) {
- ipmi_sensor_handler_t *handler;
- unsigned int poll_rate;
- void *rcb_data;
- const char *errstr;
-
- if (strcmp(tok, "poll") != 0) {
- out->printf(out, "**Only polled sensors supported\n", tok);
- return -1;
- }
+ while (tok) {
+ if (strcmp(tok, "poll") == 0) {
+ if (handler) {
+ out->printf(out, "**poll given twice in sensor\n", tok);
+ return -1;
+ }
- rv = emu_get_uint(out, toks, &poll_rate, "poll rate");
- if (rv)
- return rv;
+ rv = emu_get_uint(out, toks, &poll_rate, "poll rate");
+ if (rv)
+ return rv;
- tok = mystrtok(NULL, " \t\n", toks);
- if (!tok) {
- out->printf(out, "**No polled sensor handler given\n", tok);
- return -1;
- }
+ tok = mystrtok(NULL, " \t\n", toks);
+ if (!tok) {
+ out->printf(out, "**No polled sensor handler given\n", tok);
+ return -1;
+ }
+
+ handler = ipmi_sensor_find_handler(tok);
+ if (!handler) {
+ out->printf(out, "**Invalid sensor handler: %s\n", tok);
+ return -1;
+ }
- handler = ipmi_sensor_find_handler(tok);
- if (!handler) {
- out->printf(out, "**Invalid sensor handler: %s\n", tok);
+ rv = handler->init(mc, lun, num, toks, handler->cb_data, &rcb_data,
+ &errstr);
+ if (rv) {
+ out->printf(out, "**Error initializing sensor handler: %s\n",
+ errstr);
+ return rv;
+ }
+ } else if (strcmp(tok, "event-only") == 0) {
+ event_only = 1;
+ } else {
+ out->printf(out, "**Unknown sensor option: %s\n", tok);
return -1;
}
- rv = handler->init(mc, lun, num, toks, handler->cb_data, &rcb_data,
- &errstr);
- if (rv) {
- out->printf(out, "**Error initializing sensor handler: %s\n",
- errstr);
- return rv;
- }
+ tok = mystrtok(NULL, " \t\n", toks);
+ }
+
+ if (handler && event_only) {
+ out->printf(out, "**An event-only sensor cannot be polled\n");
+ return -1;
+ }
+ if (handler) {
rv = ipmi_mc_add_polled_sensor(mc, lun, num, type, code,
poll_rate, handler->poll, rcb_data);
@@ -423,7 +439,7 @@ sensor_add(emu_out_t *out, emu_data_t *emu, lmc_data_t *mc, char **toks)
}
}
} else {
- rv = ipmi_mc_add_sensor(mc, lun, num, type, code);
+ rv = ipmi_mc_add_sensor(mc, lun, num, type, code, event_only);
}
if (rv)
out->printf(out, "**Unable to add to sensor, error 0x%x\n", rv);
diff --git a/lanserv/extcmd.c b/lanserv/extcmd.c
index fed693d..1cd902f 100644
--- a/lanserv/extcmd.c
+++ b/lanserv/extcmd.c
@@ -167,6 +167,10 @@ extcmd_setval(void *baseloc, extcmd_info_t *t)
return NULL;
break;
+ case extcmd_ident:
+ sprintf(buf, "%u %u", (unsigned char)loc[0], (unsigned char)loc[1]);
+ break;
+
case extcmd_mac:
if (!ether_ntoa_r((struct ether_addr *) loc, buf))
return NULL;
@@ -364,7 +368,8 @@ extcmd_setvals(sys_data_t *sys,
rv = add_cmd(&cmd, ts[i].name, extcmd_setval(baseloc, ts + i), 1);
if (rv) {
sys->log(sys, OS_ERROR, NULL,
- "Out of memory in extcmd write command\n");
+ "Out of memory in extcmd write command (%d) %s\n",
+ rv, strerror(rv));
goto out;
}
}
diff --git a/lanserv/ipmi_sim.c b/lanserv/ipmi_sim.c
index c634e26..ed0b9f9 100644
--- a/lanserv/ipmi_sim.c
+++ b/lanserv/ipmi_sim.c
@@ -104,6 +104,40 @@ static char *command_file = NULL;
static int debug = 0;
static int nostdio = 0;
+/*
+ * Keep track of open sockets so we can close them on exec().
+ */
+typedef struct isim_fd {
+ int fd;
+ struct isim_fd *next;
+} isim_fd_t;
+
+static isim_fd_t *isim_fds = NULL;
+
+static void isim_add_fd(int fd)
+{
+ isim_fd_t *n = malloc(sizeof(*n));
+
+ if (!n) {
+ fprintf(stderr, "Unable to add fd to list, out of memory\n");
+ exit(1);
+ }
+
+ n->fd = fd;
+ n->next = isim_fds;
+ isim_fds = n;
+}
+
+static void isim_close_fds(void)
+{
+ isim_fd_t *n = isim_fds;
+
+ while(n) {
+ close(n->fd);
+ n = n->next;
+ }
+}
+
static void shutdown_handler(int sig);
typedef struct misc_data misc_data_t;
@@ -302,6 +336,8 @@ open_lan_fd(struct sockaddr *addr, socklen_t addr_len)
exit(1);
}
+ isim_add_fd(fd);
+
return fd;
}
@@ -443,7 +479,6 @@ ser_channel_init(void *info, channel_t *chan)
serserv_data_t *ser = chan->chan_info;
int err;
int fd;
- int opt;
struct sockaddr *addr = &ser->addr.addr.s_ipsock.s_addr;
os_hnd_fd_id_t *fd_id;
int val;
@@ -526,6 +561,9 @@ ser_channel_init(void *info, channel_t *chan)
}
}
+ if (!err)
+ isim_add_fd(fd);
+
return err;
}
@@ -692,7 +730,6 @@ emu_printf(emu_out_t *out, char *format, ...)
{
console_info_t *info = out->data;
va_list ap;
- int rv;
char buffer[500];
int start = 0;
int pos;
@@ -702,13 +739,13 @@ emu_printf(emu_out_t *out, char *format, ...)
va_end(ap);
for (pos = 0; buffer[pos]; pos++) {
if (buffer[pos] == '\n') {
- rv = write(info->outfd, buffer + start, pos - start + 1);
- rv = write(info->outfd, "\r", 1);
+ (void) write(info->outfd, buffer + start, pos - start + 1);
+ (void) write(info->outfd, "\r", 1);
start = pos + 1;
}
}
if (pos != start)
- rv = write(info->outfd, buffer + start, pos - start);
+ (void) write(info->outfd, buffer + start, pos - start);
}
static void
@@ -727,8 +764,6 @@ dummy_printf(emu_out_t *out, char *format, ...)
static unsigned char
handle_telnet(console_info_t *info, unsigned char c)
{
- int err;
-
info->tn_buf[info->tn_pos++] = c;
if ((info->tn_pos == 2) && (info->tn_buf[1] == TN_IAC))
/* Double IAC, just send it on. */
@@ -767,12 +802,12 @@ handle_telnet(console_info_t *info, unsigned char c)
send_wont:
info->tn_buf[1] = TN_WONT;
- err = write(info->outfd, info->tn_buf, 3);
+ (void) write(info->outfd, info->tn_buf, 3);
goto cmd_done;
send_dont:
info->tn_buf[1] = TN_DONT;
- err = write(info->outfd, info->tn_buf, 3);
+ (void) write(info->outfd, info->tn_buf, 3);
goto cmd_done;
cmd_done:
@@ -783,8 +818,6 @@ handle_telnet(console_info_t *info, unsigned char c)
static int
handle_user_char(console_info_t *info, unsigned char c)
{
- int rv;
-
if (info->tn_pos)
c = handle_telnet(info, c);
@@ -805,14 +838,14 @@ handle_user_char(console_info_t *info, unsigned char c)
if (info->pos > 0) {
info->pos--;
if (info->echo)
- rv = write(info->outfd, "\b \b", 3);
+ (void) write(info->outfd, "\b \b", 3);
}
break;
case 4:
if (info->pos == 0) {
if (info->echo)
- rv = write(info->outfd, "\n", 1);
+ (void) write(info->outfd, "\n", 1);
return 1;
}
break;
@@ -820,9 +853,9 @@ handle_user_char(console_info_t *info, unsigned char c)
case 10:
case 13:
if (info->echo) {
- rv = write(info->outfd, "\n", 1);
+ (void) write(info->outfd, "\n", 1);
if (info->telnet)
- rv = write(info->outfd, "\r", 1);
+ (void) write(info->outfd, "\r", 1);
}
info->buffer[info->pos] = '\0';
if (strcmp(info->buffer, "noecho") == 0) {
@@ -830,7 +863,7 @@ handle_user_char(console_info_t *info, unsigned char c)
} else {
ipmi_emu_cmd(&info->out, info->data->emu, info->buffer);
}
- rv = write(info->outfd, "> ", 2);
+ (void) write(info->outfd, "> ", 2);
info->pos = 0;
break;
@@ -838,12 +871,12 @@ handle_user_char(console_info_t *info, unsigned char c)
default:
if (info->pos >= sizeof(info->buffer)-1) {
char *msg = "\nCommand is too long, max of %d characters\n";
- rv = write(info->outfd, msg, strlen(msg));
+ (void) write(info->outfd, msg, strlen(msg));
} else {
info->buffer[info->pos] = c;
info->pos++;
if (info->echo)
- rv = write(info->outfd, &c, 1);
+ (void) write(info->outfd, &c, 1);
}
}
@@ -1201,9 +1234,8 @@ static void
handle_sigchld(int sig)
{
unsigned char c = 1;
- int rv;
- rv = write(sigpipeh[1], &c, 1);
+ (void) write(sigpipeh[1], &c, 1);
}
static ipmi_child_quit_t *child_quit_handlers;
@@ -1283,6 +1315,7 @@ ipmi_do_start_cmd(startcmd_t *startcmd)
if (pid == 0) {
char *args[4] = { "/bin/sh", "-c", cmd, NULL };
+ isim_close_fds();
execvp(args[0], args);
exit(1);
}
@@ -1555,6 +1588,8 @@ main(int argc, const char *argv[])
if (err) {
fprintf(stderr, "Unable to add console wait: 0x%x\n", err);
goto out;
+ } else {
+ isim_add_fd(nfd);
}
}
diff --git a/lanserv/ipmi_sim_cmd.5 b/lanserv/ipmi_sim_cmd.5
index 216be36..9071951 100644
--- a/lanserv/ipmi_sim_cmd.5
+++ b/lanserv/ipmi_sim_cmd.5
@@ -132,7 +132,7 @@ Add an entry to the device SDR of the MC.
.SH SENSOR COMMANDS
.TP
-\fBsensor_add\fP \fImc-addr\fP \fILUN\fP \fIsensor-num\fP \fIsensor-type\fP \fIevent-reading-code\fP [\fIpoll\fP \fIpoll_rate\fP \fIpoll_type\fP \fIpoll_type_options\fP]
+\fBsensor_add\fP \fImc-addr\fP \fILUN\fP \fIsensor-num\fP \fIsensor-type\fP \fIevent-reading-code\fP [\fIpoll\fP \fIpoll_rate\fP \fIpoll_type\fP \fIpoll_type_options\fP] [event-only]
Add a sensor to the given MC and LUN. The type of sensor is set by the
event reading code.
@@ -183,6 +183,10 @@ to be active. Generally, you use the presense bit of a sensor to mark
whether other sensors on the device are actually present. Each of the
other sensors would have one of these pointing to the presense bit.
+.I event-only
+specifies that the sensor will not be readable, it will only generate
+events (specified with a type 3 SDR).
+
.TP
\fBsensor_set_bit\fP \fImc-addr\fP \fILUN\fP \fIsensor-num\fP \fIbit-to-set\fP \fIbit-value\fP \fIgenerate-event\fP
Set the given bit to bit-value (0 or 1) for the sensor by bit number,
diff --git a/lanserv/ipmisim1.emu b/lanserv/ipmisim1.emu
index df7526e..367715b 100644
--- a/lanserv/ipmisim1.emu
+++ b/lanserv/ipmisim1.emu
@@ -9,15 +9,15 @@ mc_setbmc 0x20
mc_add 0x20 0 no-device-sdrs 0x23 9 8 0x9f 0x1291 0xf02 persist_sdr
sel_enable 0x20 1000 0x0a
+# Watchdog sensor. This must be sensor zero.
+sensor_add 0x20 0 0 35 0x6f event-only
+sensor_set_event_support 0x20 0 0 enable scanning per-state \
+ 000000000001111 000000000000000 \
+ 000000000001111 000000000000000
+
# Add a temperature sensor and its SDR. Note that sensor 0 is already
# taken as the watchdog sensor.
sensor_add 0x20 0 1 0x01 0x01
-#main_sdr_add 0x20 \
-# 00 00 51 01 31 \
-# 20 00 01 03 01 67 88 01 01 c0 0f c0 7f 38 38 00 \
-# 01 00 00 01 00 00 00 00 00 03 60 b0 00 b0 00 a0 \
-# 90 70 00 00 00 00 00 00 00 00 c6 'D 'J 't 'e 'm \
-# 'p
# Start with the value set to 0x60
sensor_set_value 0x20 0 1 0x60 0
# Set just the upper thresholds with the values 0x70, 0x90, and 0xa0
@@ -28,15 +28,10 @@ sensor_set_event_support 0x20 0 1 enable scanning per-state \
000111111000000 000111111000000
# Add a satellite MC
-mc_add 0x30 2 no-device-sdrs 0x98 0x10 1 0x80 0x1291 0xf03
+mc_add 0x30 2 no-device-sdrs 0x98 0x10 1 0x20 0x1291 0xf03
sensor_add 0x30 0 1 0x01 0x01 poll 1000 file "/tmp/file1.ipm"
-#main_sdr_add 20 \
-# 00 00 51 01 31 \
-# 30 00 01 03 02 67 88 01 01 c0 0f c0 7f 38 38 00 \
-# 01 00 00 01 00 00 00 00 00 03 60 b0 00 b0 00 a0 \
-# 90 70 00 00 00 00 00 00 00 00 c6 'D 'J 't 'e 'm \
-# 'p
+sensor_set_threshold 0x30 0 1 settable 111000 0xa0 0x90 0x70 00 00 00
sensor_set_event_support 0x30 0 1 enable scanning per-state \
000111111000000 000111111000000 \
000111111000000 000111111000000
diff --git a/lanserv/ipmisim1.sdrs b/lanserv/ipmisim1.sdrs
new file mode 100644
index 0000000..2f75ffc
--- /dev/null
+++ b/lanserv/ipmisim1.sdrs
@@ -0,0 +1,94 @@
+
+sdr type 18
+ device_slave_address 0x20
+ device_channel_number 0
+ chassis true
+ ipmb_event_gen false
+ ipmb_event_recv false
+ fru_inventory true
+ sel true
+ sdr true
+ sensor true
+ entity_id system_board
+ entity_instance 1
+ id_string "IPMI sim1"
+endsdr
+
+# Watchdog timer
+sdr type 3
+ sensor_owner_id 0x20
+ sensor_owner_lun 0
+ channel_number 0
+ sensor_number 0
+ entity_id system_board
+ entity_instance 1
+ sensor_type Watchdog_2
+ event_reading_type_code 0x6f
+ id_string "watchdog"
+endsdr
+
+# Temperature sensor on the main board
+sdr type 1
+ sensor_owner_id 0x20
+ sensor_owner_lun 0
+ channel_number 0
+ sensor_number 1
+ entity_id system_board
+ entity_instance 1
+ sensor_type Temperature
+ init_scanning true
+ init_sensor_type true
+ default_sensor_scan_on true
+ event_reading_type_code 1
+ analog_data_format unsigned
+ rate_unit none
+ modifier_unit none
+ percentage false
+ base_unit degrees_C
+ modifier_unit_code unspecified
+ linearization linear
+ m 1
+ tolerance 0
+ b 0
+ accuracy 1
+ accuracy_exp 0
+ sensor_direction input
+ r_exp 0
+ b_exp 0
+ sensor_maximum 255
+ sensor_minimum 0
+ id_string "MBTemp"
+endsdr
+
+# Temperature sensor on the sub board
+sdr type 1
+ sensor_owner_id 0x30
+ sensor_owner_lun 0
+ channel_number 0
+ sensor_number 1
+ entity_id system_board
+ entity_instance 1
+ sensor_type Temperature
+ init_scanning true
+ init_sensor_type true
+ default_sensor_scan_on true
+ event_reading_type_code 1
+ analog_data_format unsigned
+ rate_unit none
+ modifier_unit none
+ percentage false
+ base_unit degrees_C
+ modifier_unit_code unspecified
+ linearization linear
+ m 1
+ tolerance 0
+ b 0
+ accuracy 1
+ accuracy_exp 0
+ sensor_direction input
+ r_exp 0
+ b_exp 0
+ sensor_maximum 255
+ sensor_minimum 0
+ id_string "SubTemp"
+endsdr
\ No newline at end of file
diff --git a/lanserv/lan.conf b/lanserv/lan.conf
index a87cc6c..7a0f58d 100644
--- a/lanserv/lan.conf
+++ b/lanserv/lan.conf
@@ -16,7 +16,7 @@ set_working_mc 0x20
# Define an IP address and port to listen on. You can define more
# than one address/port to listen on multiple addresses. The ::
# listens on all addresses.
- addr :: 9001
+ addr localhost 9001
#addr 192.168.27.126 9000
#addr 192.168.27.200 9000
@@ -51,7 +51,7 @@ set_working_mc 0x20
# startcmd is what to execute to start a VM associated with the
# codec above (localhost 9002). It also starts a console serial port
# on port 9003 that is also used as the monitor interface.
- startcmd "$HOME/git/qemu/O/x86_64-softmmu/qemu-system-x86_64 --enable-kvm -drive file=/work/cge7/build1/tmp/deploy/images/x86_64-image.ext2,format=raw -nographic -net nic,model=e1000,macaddr=52:54:00:12:34:59 -net user,hostfwd=tcp::5555-10.0.2.15:22 -chardev socket,id=ipmi0,host=localhost,port=9002,reconnect=10 -device isa-ipmi,chardev=ipmi0,interface=bt,irq=5 -serial mon:tcp::9003,server,telnet,nowait -kernel /home/cminyard/git/linux-ipmi/O/arch/x86_64/boot/bzImage --append 'root=/dev/hda console=ttyS0,115200'"
+ startcmd "$HOME/git/qemu/O/x86_64-softmmu/qemu-system-x86_64 --enable-kvm -machine q35 -drive file=/work/cge7/build.x86-generic-64/tmp/deploy/images/small-image-x86-generic-64.ext2,format=raw -nographic -net nic,model=e1000,macaddr=52:54:00:12:34:59 -net user,hostfwd=tcp::5555-10.0.2.15:22 -chardev socket,id=ipmi0,host=localhost,port=9002,reconnect=10 -device ipmi-bmc-extern,id=bmc0,chardev=ipmi0 -device isa-ipmi-bt,bmc=bmc0 -serial mon:tcp:localhost:9003,server,telnet,nowait -kernel //work/cge7/build.x86-generic-64/tmp/deploy/images/bzImage --append 'root=/dev/sdb console=ttyS0,115200'"
# Start startcmd at startup? Default is false.
startnow false
@@ -77,7 +77,7 @@ set_working_mc 0x20
user 1 true "" "test" user 10 none md2 md5 straight
user 2 true "ipmiusr" "test" admin 10 none md2 md5 straight
- sol "/dev/ttyUSB0" 38400 history=4000 historyfru=10
+# sol "/dev/ttyUSB0" 38400 history=4000 historyfru=10
#
# Switch to a new MC
diff --git a/lanserv/lanserv_ipmi.c b/lanserv/lanserv_ipmi.c
index 219b2d8..b0a2431 100644
--- a/lanserv/lanserv_ipmi.c
+++ b/lanserv/lanserv_ipmi.c
@@ -3070,7 +3070,7 @@ ipmi_lan_tick(void *info, unsigned int time_since_last)
for (i=1; i<=MAX_SESSIONS; i++) {
if (lan->sessions[i].active) {
if (lan->sessions[i].time_left <= time_since_last) {
- msg_t msg; /* A fake message to hold the address. */
+ msg_t msg = { 0 }; /* A fake message to hold the address. */
msg.src_addr = lan->sessions[i].src_addr;
msg.src_len = lan->sessions[i].src_len;
diff --git a/lanserv/marvell-bmc/BuildingAndConfiguring.tex b/lanserv/marvell-bmc/BuildingAndConfiguring.tex
new file mode 100644
index 0000000..a4c3545
--- /dev/null
+++ b/lanserv/marvell-bmc/BuildingAndConfiguring.tex
@@ -0,0 +1,38 @@
+
+The build script
+
+build procedure
+ special files (NTP, ast1300...)
+
+How to modify the build config
+How to modify the busybox config
+
+The configuration file
+ LAN channels
+ MCs
+ users
+
+emu files
+MCs
+ sensors
+ FRU data
+
+SDRs
+
+Custom commands
+ Disable network services:
+ raw 2e 01 0f 50 00 [0|1]
+ Enables (1) or disables(0) ssh access to the BMC
+
+ Reload board FRU
+ raw 2e 02 0f 50 00 <board num>
+ Reload the board FRU information for the given board number.
+
+ Set force all fans duty cycle
+ raw 2e 03 0f 50 00 [0|<duty cycle>]
+ Set all fans to the given duty cycle. Allowed values are 30-100.
+ Setting it to zero will disable this feature
+
+ Get force all fans duty cycle
+ raw 2e 04 0f 50 00
+ Returns the current fan forced duty cycle setting.
diff --git a/lanserv/marvell-bmc/Makefile.am b/lanserv/marvell-bmc/Makefile.am
index afb5b61..6975d38 100644
--- a/lanserv/marvell-bmc/Makefile.am
+++ b/lanserv/marvell-bmc/Makefile.am
@@ -13,4 +13,8 @@ noinst_DATA = sdrs.bin
noinst_HEADERS = wiw.h
-EXTRA_DIST = main.sdrs board.sdrs fan.sdrs lan.conf netsrvc
+EXTRA_DIST = main.sdrs board.sdrs fan.sdrs lan.conf netsrvc lancontrol \
+ busybox-1.18.4.config interfaces ntp.conf marvell_bmc.config \
+ S90ast1300 SystemInfo TODO BuildingAndConfiguring.tex \
+ Build_Marvell_BMC.sh Install_Marvell_BMC.sh marvell_node.emu \
+ marvell.emu
diff --git a/lanserv/serial_ipmi.c b/lanserv/serial_ipmi.c
index e794db0..9a1806c 100644
--- a/lanserv/serial_ipmi.c
+++ b/lanserv/serial_ipmi.c
@@ -745,6 +745,7 @@ tm_setup(serserv_data_t *si)
#define VM_CAPABILITIES_IRQ 0x04
#define VM_CAPABILITIES_NMI 0x08
#define VM_CAPABILITIES_ATTN 0x10
+#define VM_CMD_FORCEOFF 0x09
struct vm_data {
unsigned char recv_msg[IPMI_SIM_MAX_MSG_LENGTH + 4];
@@ -936,7 +937,7 @@ vm_set_attn(channel_t *chan, int val, int irq)
raw_send(si, c, len);
}
-static void
+static int
vm_hw_op(channel_t *chan, unsigned int op)
{
serserv_data_t *si = chan->chan_info;
@@ -951,7 +952,7 @@ vm_hw_op(channel_t *chan, unsigned int op)
case HW_OP_POWERON:
if (chan->start_cmd)
chan->start_cmd(chan);
- return;
+ return 0;
case HW_OP_POWEROFF:
if (si->connected)
@@ -960,6 +961,11 @@ vm_hw_op(channel_t *chan, unsigned int op)
chan->stop_cmd(chan, !si->connected);
break;
+ case HW_OP_FORCEOFF:
+ if (si->connected)
+ vm_add_char(VM_CMD_FORCEOFF, c, &len);
+ break;
+
case HW_OP_SEND_NMI:
vm_add_char(VM_CMD_SEND_NMI, c, &len);
break;
@@ -972,13 +978,18 @@ vm_hw_op(channel_t *chan, unsigned int op)
vm_add_char(VM_CMD_DISABLE_IRQ, c, &len);
break;
+ case HW_OP_CHECK_POWER:
+ return si->connected;
+ break;
+
default:
- return;
+ return 0;
}
c[len++] = VM_CMD_CHAR;
raw_send(si, c, len);
+ return 0;
}
static void
diff --git a/lib/domain.c b/lib/domain.c
index 1a2a1b3..718ffa9 100644
--- a/lib/domain.c
+++ b/lib/domain.c
@@ -474,6 +474,12 @@ _ipmi_put_domain_fully_up(ipmi_domain_t *domain, char *name)
ipmi_unlock(domain->domain_lock);
}
+int
+ipmi_domain_is_fully_up(ipmi_domain_t *domain)
+{
+ return domain->fully_up_count == 0;
+}
+
/***********************************************************************
*
* Domain data structure creation and destruction
diff --git a/lib/event.c b/lib/event.c
index b69cf24..8230e55 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -385,9 +385,9 @@ sensor_event_call(ipmi_sensor_t *sensor, void *cb_data)
raw_value = data[11];
value = 0.0;
- if ((data[10] >> 6) == 2) {
+ if ((data[10] >> 6) == 1) {
rv = ipmi_sensor_convert_from_raw(sensor, raw_value, &value);
- if (!rv)
+ if (rv)
value_present = IPMI_RAW_VALUE_PRESENT;
else
value_present = IPMI_BOTH_VALUES_PRESENT;
diff --git a/lib/lanparm.c b/lib/lanparm.c
index bb36264..f8b075f 100644
--- a/lib/lanparm.c
+++ b/lib/lanparm.c
@@ -886,6 +886,7 @@ struct ipmi_lan_config_s
unsigned char max_priv_for_cipher_suite_supported;
unsigned char max_priv_for_cipher_suite[16];
+ /* See the note in the gnd function foro weirdness about this field. */
unsigned char num_alert_destinations;
unsigned char vlan_tag_supported;
alert_dest_type_t *alert_dest_type;
@@ -1095,6 +1096,12 @@ static int gnd(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
if (num == 0)
return 0;
+ /*
+ * This is important! The number in this field is the number of
+ * non-volatile destinations. There is a volatile destination
+ * at zero that is always present, and at least on non-volatile
+ * field is required if this paramter is non-zero.
+ */
num++;
lanc->alert_dest_type = ipmi_mem_alloc(sizeof(alert_dest_type_t) * num);
@@ -1554,7 +1561,7 @@ got_parm(ipmi_lanparm_t *lanparm,
if (lanc->num_alert_destinations == 0)
goto done;
lanc->curr_parm = IPMI_LANPARM_DEST_VLAN_TAG;
- lanc->curr_sel = 1;
+ lanc->curr_sel = 0;
}
break;
diff --git a/lib/normal_fru.c b/lib/normal_fru.c
index 91106cb..e1ac548 100644
--- a/lib/normal_fru.c
+++ b/lib/normal_fru.c
@@ -4801,11 +4801,10 @@ process_fru_info(ipmi_fru_t *fru)
goto check_done;
}
if (foff[i].offset >= foff[j].offset) {
- ipmi_log(IPMI_LOG_ERR_INFO,
+ ipmi_log(IPMI_LOG_WARNING,
"%snormal_fru.c(process_fru_info):"
" FRU fields did not occur in the correct order",
_ipmi_fru_get_iname(fru));
- return EBADF;
}
}
check_done:
diff --git a/lib/rakp.c b/lib/rakp.c
index d4ffeef..6afd750 100644
--- a/lib/rakp.c
+++ b/lib/rakp.c
@@ -482,7 +482,7 @@ rakp_hmac_c2(rakp_info_t *info,
return EINVAL;
HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 58+idata[57], integ_data, &ilen);
if (memcmp(data+40, integ_data, rinfo->key_len) != 0)
- return EKEYREJECTED;
+ return EINVAL;
/* Now generate the SIK */
p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen);
diff --git a/lib/sensor.c b/lib/sensor.c
index bb5971e..c6d9546 100644
--- a/lib/sensor.c
+++ b/lib/sensor.c
@@ -3695,9 +3695,9 @@ ipmi_sensor_event(ipmi_sensor_t *sensor, ipmi_event_t *event)
raw_value = data[11];
value = 0.0;
- if ((data[10] >> 6) == 2) {
+ if ((data[10] >> 6) == 1) {
rv = ipmi_sensor_convert_from_raw(sensor, raw_value, &value);
- if (!rv)
+ if (rv)
value_present = IPMI_RAW_VALUE_PRESENT;
else
value_present = IPMI_BOTH_VALUES_PRESENT;
diff --git a/man/Makefile.am b/man/Makefile.am
index dc26492..632f55b 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -1,5 +1,6 @@
man_MANS = ipmi_ui.1 openipmicmd.1 openipmish.1 ipmi_cmdlang.7 \
- openipmigui.1 openipmi_conparms.7 solterm.1 rmcp_ping.1
+ openipmigui.1 openipmi_conparms.7 solterm.1 rmcp_ping.1 \
+ openipmi_eventd.1
EXTRA_DIST = $(man_MANS)
diff --git a/man/openipmi_eventd.1 b/man/openipmi_eventd.1
new file mode 100644
index 0000000..9f953a5
--- /dev/null
+++ b/man/openipmi_eventd.1
@@ -0,0 +1,168 @@
+.TH openipmi_eventd 1 03/4/15 OpenIPMI "IPMI event handler"
+
+.SH NAME
+openipmi_eventd \- An IPMI event handler
+
+.SH SYNOPSIS
+.B openipmi_eventd
+.BI "<domain\ name>"
+.BI "<connection\ parms>"
+.BI "<options>"
+.BI "<program> [<parm1> [<parm2> [...]]]"
+.SH DESCRIPTION
+The
+.BR openipmi_eventd
+program listens for IPMI events for the given connection and sends them
+to another program to process, or to a file.
+
+.SH PARAMETERS
+.TP
+.BI <domain\ name>
+The name to use for the OpenIPMI domain. This will appear in logs and
+some names.
+
+.TP
+.BI <connection\ parms>
+The parameters for the connection depend on the connection type.
+These are all described in openipmi_conparms (7)
+
+.TP
+.BI <options>
+Zero or more of the options defined in OPTIONS below.
+
+.TP
+.BI <program>\ [<parm1>\ [<parm2>\ [...]]]
+The program to run. This must be the full path to the program. Any
+given parameters are passed to the program before any IPMI parameters.
+
+.SH OPTIONS
+.TP
+\fB\-f\fR filename, \fB\-\-outfile\fR filename
+Send all events to the given file
+
+.TP
+\fB\-k\fR, \fB\-\-exec\-now\fR
+Immediately spawn the given program and send the event information to that
+program's standard input. The program should not quit, if it does then
+this program will exit with an error.
+
+.TP
+\fB\-i\fR, \fB\-\-event\-stdin\fR
+Send the event information to the program's standard input instead of
+the commandline.
+
+.TP
+\fB\-e\fR, \fB\-\-delete\-events\fR
+Delete events from the SEL (System Event Log) once they have been
+processed. Note that the program has to have handled the event
+without error for the event to be deleted. Otherwise the events are
+not deleted from the SEL.
+
+.TP
+\fB\-b\fR, \fB\-\-dont\-daemonize\fR
+Do not daemonize the program, run it as a foreground process.
+
+.TP
+\fB\-d\fR, \fB\-\-debug\fR
+Debug the program, turn on output, send all logs to stderr, and do not
+run the process as a daemon.
+
+.SH "USAGE"
+When started, this program will connect to the given IPMI domain,
+ignore all existing logs, and set up to listen from logs from all
+sources. When an event comes in, it will handle the event depending
+on how it is configured.
+
+By default the program will be called on each log and the event information
+passed on the program's command line. The first parameter (after the ones
+given on the
+.BR openipmi_eventd
+command line) will be the event type, the rest are key-value pairs as
+defined below.
+
+If
+.BI \-i
+is given on the commandline, instead of passing in the event information
+on the command line, it will be passed into the program's standard input.
+The first line will be the event type, and each line will have a key-value
+pair up until the last line, which will be
+.BI endevent.
+
+If
+.BI \-k
+is given on the command line, the program will be started immediately and
+expected to take events on its standard input as they come in. Each
+event will start with an event type, contain key-value pairs, and end
+in
+.BI endevent.
+
+.SH "EVENT KEY-VALUE PAIRS"
+
+The first line and parameter of an event is always the event type
+(either
+.BI threshold
+,
+.BI discrete
+, or
+.BI unknown
+). Then the following
+then the following, in no particular order. When sending to a file,
+or another program via standard input,
+.BI endevent
+will mark the end of an event.
+
+.RS
+.IP assert\ true|false
+If true, the event is being asserted (the alarm
+present). If false, the alarm was present but has now gone
+away.
+.IP eventtype\ <num>
+The event type, per the IPMI specification.
+.IP eventtime\ <num>
+The time (in seconds) for the IPMI event. It is 64 bits.
+.IP eventdata\ <vals>
+The raw event data, vals is a list of hex numbers.
+.IP id\ <name>
+The OpenIPMI id of the sensor. This is in the format:
+.BI <entity_id>.<entity_instance>.<sensor_name>
+where the entity id and instance identify the object being
+monitored and the sensor names comes from the sensor. Only
+for discrete and threshold events.
+.IP val\ <floatnum>
+The sensor value that cause the event, in floating point format.
+Optional and only present for threshold sensors.
+.IP raw\ <hexnum>
+The sensor value that cause the event, in raw (hex) format. Optional
+and only present for threshold sensors.
+.IP off\ <num>
+The bit in the sensor that caused the event, only present for discrete sensors.
+.IP severity
+The severity of the event. For discrete sensors this optional and is a
+number between 0 and 14. Them meaning depends on the specific sensor type.
+For threshold sensors this is one of:
+.RS
+.IP lower_non_critical
+.IP lower_critical
+.IP lower_non_recoverable
+.IP upper_non_critical
+.IP upper_critical
+.IP upper_non_recoverable
+.RE
+.IP prevseverity - The severity before the event, optional and only present
+for discrete sensors.
+.IP direction going_low|going_high
+The direction of the event, only for threshold sensors. This can be
+difficult to understand and is not consistent on IPMI systems. The
+IPMI specifiation does define what this means. For instance, what
+does an assertion of an upper critcal event going low mean?
+.RE
+
+.SH "SEE ALSO"
+.BR openipmi_conparms (7)
+
+.SH "KNOWN PROBLEMS"
+None
+
+.SH AUTHOR
+.PP
+Corey Minyard <cminyard@mvista.com>
diff --git a/sample/Makefile.am b/sample/Makefile.am
index febba2f..06278bd 100644
--- a/sample/Makefile.am
+++ b/sample/Makefile.am
@@ -2,7 +2,7 @@
AM_CFLAGS = -Wall -Wsign-compare -I$(top_builddir)/include \
-I$(top_srcdir)/include -DIPMI_CHECK_LOCKS
-bin_PROGRAMS = openipmicmd solterm rmcp_ping
+bin_PROGRAMS = openipmicmd solterm rmcp_ping openipmi_eventd
noinst_PROGRAMS = ipmisample ipmisample2 ipmisample3 ipmi_serial_bmc_emu \
ipmi_dump_sensors waiter_sample
@@ -31,6 +31,12 @@ waiter_sample_LDADD = $(top_builddir)/utils/libOpenIPMIutils.la \
$(top_builddir)/unix/libOpenIPMIposix.la \
$(OPENSSLLIBS)
+openipmi_eventd_SOURCES = eventd.c
+openipmi_eventd_LDADD = $(top_builddir)/utils/libOpenIPMIutils.la \
+ $(top_builddir)/lib/libOpenIPMI.la \
+ $(top_builddir)/unix/libOpenIPMIposix.la \
+ $(OPENSSLLIBS)
+
ipmi_dump_sensors_SOURCES = dump_sensors.c
ipmi_dump_sensors_LDADD = $(top_builddir)/utils/libOpenIPMIutils.la \
$(top_builddir)/lib/libOpenIPMI.la \
@@ -65,4 +71,4 @@ install-data-local:
$(LN_S) openipmicmd $(DESTDIR)$(bindir)/ipmicmd
uninstall-local:
- rm -f $(DESTDIR)$(bindir)/ipmicmd
\ No newline at end of file
+ rm -f $(DESTDIR)$(bindir)/ipmicmd
diff --git a/sample/eventd.c b/sample/eventd.c
new file mode 100644
index 0000000..1ae1600
--- /dev/null
+++ b/sample/eventd.c
@@ -0,0 +1,770 @@
+/*
+ * eventd.c
+ *
+ * OpenIPMI event logging daemon
+ *
+ * This program takes IPMI events and calls an external program to
+ * handle them. See the man page for usage details.
+ *
+ * Author: Corey Minyard <cminyard@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <time.h>
+#include <syslog.h>
+
+#include <OpenIPMI/ipmiif.h>
+#include <OpenIPMI/ipmi_err.h>
+#include <OpenIPMI/ipmi_posix.h>
+
+#define STDERR_IPMIERR(err, format, ...) \
+ do { \
+ char errstr[128]; \
+ ipmi_get_error_string(err, errstr, sizeof(errstr)); \
+ fprintf(stderr, "%s: " format ": %s\n", domainname, ##__VA_ARGS__, \
+ errstr); \
+ } while(0)
+
+#define SYSLOG_IPMIERR(level, err, format, ...) \
+ do { \
+ char errstr[128]; \
+ ipmi_get_error_string(err, errstr, sizeof(errstr)); \
+ syslog(level, "%s: " format ": %s", domainname, ##__VA_ARGS__, errstr);\
+ } while(0)
+
+#define debug_printf(format, ...) \
+ do { \
+ if (debug) \
+ printf(format, ##__VA_ARGS__); \
+ } while(0)
+
+static const char *progname;
+static char **prog;
+static int num_prog;
+static bool progstdio;
+static FILE *outfile;
+static char *domainname;
+static bool domain_up;
+static bool delete_events;
+static int debug;
+static int childpid = -1;
+
+static char *indent_str(const char *instr, const char *indent)
+{
+ int p, o;
+ int ilen = strlen(indent);
+ size_t extra = 0;
+ char *s;
+
+ for (p = 0; instr[p]; p++) {
+ if (instr[p] == '\n')
+ extra += ilen;
+ }
+ if (extra == 0)
+ return (char *) instr;
+ s = malloc(strlen(instr) + extra + 1);
+ if (!s)
+ return NULL;
+ for (p = 0, o = 0; instr[p]; p++) {
+ s[o++] = instr[p];
+ if (instr[p] == '\n') {
+ memcpy(s + o, indent, ilen);
+ o += ilen;
+ }
+ }
+ s[o] = '\0';
+ return s;
+}
+
+static void con_usage(const char *name, const char *help, void *cb_data)
+{
+ char *newhelp = indent_str(help, " ");
+ printf("\n %s%s", name, newhelp);
+ if (newhelp != help)
+ free(newhelp);
+}
+
+static void
+usage(void)
+{
+ printf("Usage:\n");
+ printf(" %s <domain> <con_parms> [-k] [-i] [-e] [-d] [-b] [-f <filename>] <program> [<parm1> [<parm2> [...]]]\n",
+ progname);
+ printf("<domain> is a name given to locally identify the connection.\n");
+ printf("Options are:\n");
+ printf(" -k, --exec-now - Execute the program at startup and feed it\n");
+ printf(" events through stdin.\n");
+ printf(" -i, --event-stdin - Execute the program for each event, but\n");
+ printf(" feed it input through stdin.\n");
+ printf(" -e, --delete-events - Delete each event after processing.\n");
+ printf(" -d, --debug - Enable debugging\n");
+ printf(" -b, --dont-daemonize - Run the program in foreground.\n");
+ printf(" -f, --outfile - Send the output to the given file instead of\n");;
+ printf(" spawning another program.\n");
+ printf("<con_parms> is:");
+ ipmi_parse_args_iter_help(con_usage, NULL);
+}
+
+static int
+send_parms_to_file(char *type, char **parms1, int num_parms1,
+ char **parms2, int num_parms2)
+{
+ int i;
+ fprintf(outfile, "%s\n", type);
+ for (i = 0; i + 1 < num_parms1; i += 2)
+ fprintf(outfile, "%s %s\n", parms1[i], parms1[i + 1]);
+ for (i = 0; i + 1 < num_parms2; i += 2)
+ fprintf(outfile, "%s %s\n", parms2[i], parms2[i + 1]);
+ fprintf(outfile, "endevent\n");
+ if (fflush(outfile) == -1) {
+ syslog(LOG_CRIT, "%s: Destination end of pipe failed: %s\n",
+ domainname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+newpipe(FILE **retfile)
+{
+ int fds[2];
+ FILE *f;
+
+ if (pipe(fds) == -1) {
+ syslog(LOG_ERR, "%s: Unable to open pipe to subprogram: %s",
+ domainname, strerror(errno));
+ return -1;
+ }
+
+ f = fdopen(fds[1], "w");
+ if (!f) {
+ syslog(LOG_ERR, "%s: Unable to fdopen pipe to subprogram: %s",
+ domainname, strerror(errno));
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+
+ *retfile = f;
+ return fds[0];
+}
+
+static void
+send_event_to_prog(char *type,
+ ipmi_event_t *event,
+ char **parms,
+ int num_parms)
+{
+ char typestr[30];
+ char timestr[30];
+ char datastr[128];
+ char *parms2[6];
+ int num_parms2 = 0;
+ pid_t pid;
+ int infd = -1;
+ bool handled = false;
+
+ if (event) {
+ int pos = 0;
+ unsigned int i, len;
+ unsigned char eventdata[16];
+
+ parms2[num_parms2++] = "eventtype";
+ parms2[num_parms2++] = typestr;
+ snprintf(typestr, sizeof(typestr), "0x%x", ipmi_event_get_type(event));
+
+ parms2[num_parms2++] = "eventtime";
+ parms2[num_parms2++] = timestr;
+ snprintf(timestr, sizeof(timestr), "%lld",
+ (long long) ipmi_event_get_timestamp(event));
+
+ parms2[num_parms2++] = "eventdata";
+ parms2[num_parms2++] = datastr;
+ datastr[0] = '\0';
+ len = ipmi_event_get_data_len(event);
+ if (len > sizeof(eventdata))
+ len = sizeof(eventdata);
+ ipmi_event_get_data(event, eventdata, 0, len);
+ for (i = 0; i < len; i++) {
+ pos += snprintf(datastr + pos, sizeof(datastr) - pos, " 0x%2.2x",
+ eventdata[i]);
+ }
+ }
+
+ if (!domain_up)
+ goto out;
+
+ if (outfile) {
+ if (send_parms_to_file(type, parms, num_parms, parms2, num_parms2))
+ /* The remote end is broken, give up. */
+ exit(1);
+ handled = true;
+ goto out;
+ }
+
+ if (progstdio) {
+ infd = newpipe(&outfile);
+ if (infd == -1)
+ goto out_close;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ syslog(LOG_ERR, "%s: Unable to fork: %s\n", domainname,
+ strerror(errno));
+ } else if (pid > 0) {
+ int rv, status;
+
+ if (outfile) {
+ if (!send_parms_to_file(type, parms, num_parms, parms2, num_parms2))
+ handled = true;
+
+ /*
+ * Close the output here, instead of later, to give a hint to
+ * the program receiving the data that we are done.
+ */
+ fclose(outfile);
+ outfile = NULL;
+ }
+
+ /* Wait here so multiple events don't get out of order. */
+ rv = waitpid(pid, &status, 0);
+
+ /* If the calling program failed, don't delete the event. */
+ if (rv == -1)
+ handled = false;
+ else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ handled = false;
+ } else if (outfile) {
+ fclose(outfile);
+ close(0);
+ if (dup(infd) != 0)
+ exit(1);
+ close(infd);
+ execv(prog[0], prog);
+ syslog(LOG_ERR, "%s: Unable to execute program: %s\n", domainname,
+ strerror(errno));
+ exit(1);
+ } else {
+ char **execvals;
+ execvals = malloc((num_parms + num_parms2 + num_prog + 2)
+ * sizeof(char *));
+ if (!execvals) {
+ syslog(LOG_ERR, "%s: Out of memory allocating execvals",
+ domainname);
+ goto out_close;
+ }
+
+ memcpy(execvals, prog, num_prog * sizeof(char *));
+ execvals[num_prog] = type;
+ memcpy(execvals + num_prog + 1, parms, num_parms * sizeof(char *));
+ memcpy(execvals + num_prog + num_parms + 1, parms2,
+ num_parms2 * sizeof(char *));
+ execvals[num_prog + num_parms + num_parms2 + 1] = NULL;
+
+ execv(execvals[0], execvals);
+ syslog(LOG_ERR, "%s: Unable to execute program: %s\n", domainname,
+ strerror(errno));
+ exit(1);
+ }
+
+ out_close:
+ if (outfile) {
+ fclose(outfile);
+ outfile = NULL;
+ }
+ out:
+ if (handled && event && delete_events)
+ ipmi_event_delete(event, NULL, NULL);
+ return;
+}
+
+static void
+send_sensor_event_to_prog(ipmi_sensor_t *sensor,
+ enum ipmi_event_dir_e dir,
+ ipmi_event_t *event,
+ char *type,
+ char **parms,
+ int num_parms)
+{
+ ipmi_entity_t *ent = ipmi_sensor_get_entity(sensor);
+ int id, instance, pos;
+ char idstr[128];
+
+
+ parms[num_parms++] = "assert";
+ parms[num_parms++] = (dir == IPMI_ASSERTION) ? "true" : "false";
+
+ parms[num_parms++] = "id";
+ parms[num_parms++] = idstr;
+ id = ipmi_entity_get_entity_id(ent);
+ instance = ipmi_entity_get_entity_instance(ent);
+ pos = snprintf(idstr, sizeof(idstr), "%d.%d.", id, instance);
+ ipmi_sensor_get_id(sensor, idstr + pos, sizeof(idstr) - pos - 1);
+ idstr[127] = '\0';
+
+ send_event_to_prog(type, event, parms, num_parms);
+}
+
+/*
+ * Enough to add the id.
+ */
+#define MAX_EXTRA_PARMS 4
+
+char *thresh_to_severity[6] = {
+ "lower_non_critical",
+ "lower_critical",
+ "lower_non_recoverable",
+ "upper_non_critical",
+ "upper_critical",
+ "upper_non_recoverable"
+};
+
+static int
+sensor_threshold_event_handler(ipmi_sensor_t *sensor,
+ enum ipmi_event_dir_e dir,
+ enum ipmi_thresh_e threshold,
+ enum ipmi_event_value_dir_e high_low,
+ enum ipmi_value_present_e value_present,
+ unsigned int raw_value,
+ double value,
+ void *cb_data,
+ ipmi_event_t *event)
+{
+ char *parms[10 + MAX_EXTRA_PARMS];
+ int num_parms = 0;
+ char valstr[30];
+ char rawstr[30];
+
+ debug_printf("threshold event handler\n");
+
+ parms[num_parms++] = "severity";
+ parms[num_parms++] = thresh_to_severity[threshold];
+
+ parms[num_parms++] = "direction";
+ parms[num_parms++] = high_low == IPMI_GOING_LOW ?
+ "going_low" : "going_high";
+
+ if (value_present == IPMI_BOTH_VALUES_PRESENT) {
+ parms[num_parms++] = "val";
+ parms[num_parms++] = valstr;
+ snprintf(valstr, sizeof(valstr), "%f", value);
+ parms[num_parms++] = "raw";
+ parms[num_parms++] = rawstr;
+ snprintf(rawstr, sizeof(rawstr), "0x%2.2x", raw_value);
+ } else if (value_present == IPMI_RAW_VALUE_PRESENT) {
+ parms[num_parms++] = "raw";
+ parms[num_parms++] = rawstr;
+ snprintf(rawstr, sizeof(rawstr), "0x%2.2x", raw_value);
+ }
+
+ send_sensor_event_to_prog(sensor, dir, event, "threshold",
+ parms, num_parms);
+
+ /* Don't pass this on. */
+ return IPMI_EVENT_HANDLED;
+}
+
+static int
+sensor_discrete_event_handler(ipmi_sensor_t *sensor,
+ enum ipmi_event_dir_e dir,
+ int offset,
+ int severity,
+ int prev_severity,
+ void *cb_data,
+ ipmi_event_t *event)
+{
+ char *parms[6 + MAX_EXTRA_PARMS];
+ int num_parms = 0;
+ char sevstr[30];
+ char prevstr[30];
+ char offstr[30];
+
+ debug_printf("discrete event handler\n");
+
+ parms[num_parms++] = "offset";
+ parms[num_parms++] = offstr;
+ snprintf(offstr, sizeof(offstr), "%d", offset);
+
+ if (severity != -1) {
+ parms[num_parms++] = "severity";
+ parms[num_parms++] = sevstr;
+ snprintf(sevstr, sizeof(sevstr), "%d", severity);
+ }
+
+ if (prev_severity != -1) {
+ parms[num_parms++] = "prevseverity";
+ parms[num_parms++] = prevstr;
+ snprintf(prevstr, sizeof(prevstr), "%d", prev_severity);
+ }
+
+ send_sensor_event_to_prog(sensor, dir, event, "discrete",
+ parms, num_parms);
+
+ /* Don't pass this on. */
+ return IPMI_EVENT_HANDLED;
+}
+
+static void
+default_event_handler(ipmi_domain_t *domain,
+ ipmi_event_t *event,
+ void *event_data)
+{
+ debug_printf("default event handler\n");
+
+ send_event_to_prog("unknown", event, NULL, 0);
+}
+
+/* Whenever the status of a sensor changes, the function is called
+ We display the information of the sensor if we find a new sensor
+*/
+static void
+sensor_change(enum ipmi_update_e op,
+ ipmi_entity_t *ent,
+ ipmi_sensor_t *sensor,
+ void *cb_data)
+{
+ int id, instance;
+ char name[33];
+ int rv;
+
+ id = ipmi_entity_get_entity_id(ent);
+ instance = ipmi_entity_get_entity_instance(ent);
+ ipmi_sensor_get_id(sensor, name, 32);
+ if (op == IPMI_ADDED) {
+ debug_printf("Sensor added: %d.%d.%s\n", id, instance, name);
+
+ if (ipmi_sensor_get_event_reading_type(sensor)
+ == IPMI_EVENT_READING_TYPE_THRESHOLD)
+ rv = ipmi_sensor_add_threshold_event_handler
+ (sensor,
+ sensor_threshold_event_handler,
+ NULL);
+ else
+ rv = ipmi_sensor_add_discrete_event_handler
+ (sensor,
+ sensor_discrete_event_handler,
+ NULL);
+ if (rv) {
+ SYSLOG_IPMIERR(LOG_CRIT, rv, "Unable to add sensor event handler");
+ exit(1);
+ }
+ }
+}
+
+/* Whenever the status of an entity changes, the function is called
+ When a new entity is created, we search all sensors that belong
+ to the entity */
+static void
+entity_change(enum ipmi_update_e op,
+ ipmi_domain_t *domain,
+ ipmi_entity_t *entity,
+ void *cb_data)
+{
+ int rv;
+ int id, instance;
+
+ id = ipmi_entity_get_entity_id(entity);
+ instance = ipmi_entity_get_entity_instance(entity);
+ if (op == IPMI_ADDED) {
+ debug_printf("Entity added: %d.%d\n", id, instance);
+ /* Register callback so that when the status of a
+ sensor changes, sensor_change is called */
+ rv = ipmi_entity_add_sensor_update_handler(entity,
+ sensor_change,
+ entity);
+ if (rv) {
+ SYSLOG_IPMIERR(LOG_CRIT, rv, "Unable to add sensor update handler");
+ exit(1);
+ }
+ }
+}
+
+/* After we have established connection to domain, this function get called
+ At this time, we can do whatever things we want to do. Herr we want to
+ search all entities in the system */
+void
+setup_done(ipmi_domain_t *domain,
+ int err,
+ unsigned int conn_num,
+ unsigned int port_num,
+ int still_connected,
+ void *user_data)
+{
+ int rv;
+
+ if (err) {
+ SYSLOG_IPMIERR(LOG_CRIT, err, "Unable to connect to domain");
+ exit(1);
+ }
+
+ rv = ipmi_domain_add_event_handler(domain, default_event_handler, NULL);
+ if (rv) {
+ SYSLOG_IPMIERR(LOG_CRIT, rv, "Unable to add default event handler");
+ exit(1);
+ }
+
+ /* Register a callback functin entity_change. When a new entities
+ is created, entity_change is called */
+ rv = ipmi_domain_add_entity_update_handler(domain, entity_change, domain);
+ if (rv) {
+ SYSLOG_IPMIERR(LOG_CRIT, rv, "Unable to add entity update handler");
+ exit(1);
+ }
+}
+
+static os_handler_t *os_hnd;
+
+static void
+handle_openipmi_vlog(os_handler_t *handler,
+ const char *format,
+ enum ipmi_log_type_e log_type,
+ va_list ap)
+{
+ int level;
+ char *newformat;
+
+ switch(log_type)
+ {
+ case IPMI_LOG_INFO: level = LOG_INFO; break;
+ case IPMI_LOG_WARNING: level = LOG_WARNING; break;
+ case IPMI_LOG_SEVERE: level = LOG_ERR; break;
+ case IPMI_LOG_FATAL: level = LOG_CRIT; break;
+ case IPMI_LOG_ERR_INFO: level = LOG_WARNING; break;
+
+ case IPMI_LOG_DEBUG_START:
+ case IPMI_LOG_DEBUG:
+ case IPMI_LOG_DEBUG_CONT:
+ case IPMI_LOG_DEBUG_END:
+ level = LOG_DEBUG;
+ break;
+ default:
+ level = LOG_NOTICE;
+ }
+
+ newformat = malloc(strlen(format) + strlen(domainname) + 3);
+ if (!newformat) {
+ vsyslog(level, format, ap);
+ return;
+ }
+
+ strcpy(newformat, domainname);
+ strcat(newformat, ": ");
+ strcat(newformat, format);
+ vsyslog(level, newformat, ap);
+ free(newformat);
+}
+
+static void
+fully_up(ipmi_domain_t *domain, void *cb_data)
+{
+ debug_printf("Fully up!\n");
+ domain_up = 1;
+}
+
+static void
+sigchld_handler(int sig)
+{
+ syslog(LOG_CRIT, "%s: Child process failed\n", domainname);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int rv;
+ int curr_arg = 2;
+ ipmi_args_t *args;
+ ipmi_con_t *con;
+ bool execnow = false;
+ bool daemonize = true;
+ char *outfname = NULL;
+ int syslog_options = 0;
+
+ if (argc < 2) {
+ fprintf(stderr, "No domain name given\n");
+ exit(1);
+ }
+
+ progname = argv[0];
+ domainname = argv[1];
+
+ /* OS handler allocated first. */
+ os_hnd = ipmi_posix_setup_os_handler();
+ if (!os_hnd) {
+ fprintf(stderr, "ipmi_smi_setup_con: Unable to allocate os handler\n");
+ exit(1);
+ }
+
+ /* Override the default log handler. */
+ os_hnd->set_log_handler(os_hnd, handle_openipmi_vlog);
+
+ rv = ipmi_init(os_hnd);
+ if (rv) {
+ STDERR_IPMIERR(rv, "Error in ipmi initialization");
+ exit(1);
+ }
+
+ rv = ipmi_parse_args2(&curr_arg, argc, argv, &args);
+ if (rv) {
+ STDERR_IPMIERR(rv, "Error parsing command arguments, argument %d",
+ curr_arg);
+ usage();
+ exit(1);
+ }
+
+ while (curr_arg < argc && argv[curr_arg][0] == '-') {
+ int a = curr_arg;
+ curr_arg++;
+ if (strcmp(argv[a], "--") == 0)
+ break;
+ if ((strcmp(argv[a], "-i") == 0) ||
+ (strcmp(argv[a], "--event-stdin") == 0))
+ progstdio = true;
+ else if ((strcmp(argv[a], "-k") == 0) ||
+ (strcmp(argv[a], "--exec-now") == 0))
+ execnow = true;
+ else if ((strcmp(argv[a], "-e") == 0) ||
+ (strcmp(argv[a], "--delete-events") == 0))
+ delete_events = true;
+ else if ((strcmp(argv[a], "-d") == 0) ||
+ (strcmp(argv[a], "--debug") == 0)) {
+ debug++;
+ daemonize = false;
+ } else if ((strcmp(argv[a], "-b") == 0) ||
+ (strcmp(argv[a], "--dont-daemonize") == 0))
+ daemonize = false;
+ else if ((strcmp(argv[a], "-f") == 0) ||
+ (strcmp(argv[a], "--outfile") == 0)) {
+ if (curr_arg == argc) {
+ fprintf(stderr, "-f given, but no filename given\n");
+ exit(1);
+ }
+ outfname = argv[curr_arg];
+ curr_arg++;
+ } else {
+ fprintf(stderr, "Unknown parameter: %s\n", argv[a]);
+ exit(1);
+ }
+
+ }
+
+ prog = argv + curr_arg;
+ num_prog = argc - curr_arg;
+
+ if (debug)
+ syslog_options |= LOG_PERROR;
+
+ openlog("openipmi_syslog", syslog_options, LOG_DAEMON);
+
+ rv = ipmi_args_setup_con(args, os_hnd, NULL, &con);
+ if (rv) {
+ STDERR_IPMIERR(rv, "ipmi_ip_setup_con failed");
+ exit(1);
+ }
+
+ rv = ipmi_open_domain(domainname, &con, 1, setup_done, NULL, fully_up, NULL,
+ NULL, 0, NULL);
+ if (rv) {
+ STDERR_IPMIERR(rv, "ipmi_open domain failed");
+ exit(1);
+ }
+
+ if (outfname) {
+ if (curr_arg != argc || execnow) {
+ fprintf(stderr, "You can't specify a program or -k"
+ " along with -f\n");
+ exit(1);
+ }
+ outfile = fopen(outfname, "a");
+ if (!outfile) {
+ fprintf(stderr, "Unable to output output file %s: %s\n", outfname,
+ strerror(errno));
+ exit(1);
+ }
+ } else if (curr_arg == argc) {
+ fprintf(stderr, "No program given to execute on an IPMI event\n");
+ exit(1);
+ }
+
+ if (execnow) {
+ /* Only watch for child processes if we keep it around. */
+ if (signal(SIGCHLD, sigchld_handler) == SIG_ERR) {
+ fprintf(stderr, "Unable to install sigchld handler: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+
+ /*
+ * We have to daemonize before we fork or sigchld won't work.
+ */
+ if (daemonize)
+ daemon(0, 0);
+
+ if (execnow) {
+ int infd = newpipe(&outfile);
+
+ if (infd == -1) {
+ fprintf(stderr, "Unable to open pipe, see syslog for errors\n");
+ exit(1);
+ }
+
+ childpid = fork();
+ if (childpid < 0) {
+ syslog(LOG_CRIT, "%s: Unable to fork: %s\n", domainname,
+ strerror(errno));
+ exit(1);
+ } else if (childpid == 0) {
+ close(0);
+ if (dup(infd) != 0) {
+ syslog(LOG_CRIT, "%s: Dup didn't set stdin\n", domainname);
+ exit(1);
+ }
+ close(infd);
+ execv(prog[0], prog);
+ syslog(LOG_CRIT, "%s: Unable to exec %s: %s\n", domainname, prog[0],
+ strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* Let the selector code run the select loop. */
+ os_hnd->operation_loop(os_hnd);
+
+ /* Technically, we can't get here, but just to be sure... */
+ os_hnd->free_os_handler(os_hnd);
+ return 0;
+}
diff --git a/swig/python/openipmigui/gui.py b/swig/python/openipmigui/gui.py
index 39801e6..3226cd1 100644
--- a/swig/python/openipmigui/gui.py
+++ b/swig/python/openipmigui/gui.py
@@ -38,6 +38,7 @@ import gui_errstr
import gui_cmdwin
import gui_list
import gui_popup
+import gui_winsys
init_treenamewidth = 150
init_sashposition = 400
@@ -49,14 +50,6 @@ init_logevents = False
init_fullevents = False
init_impt_objs = [ ]
-try:
- winsys = self.tk.eval("return [ tk windowingsystem ]")
- pass
-except:
- # Assume x11
- winsys = "x11"
- pass
-
refresh_timer_time = 10000
class IPMITreeDummyItem:
@@ -218,7 +211,7 @@ class IPMIGUI(Tix.Frame):
self.tree.hlist.bind("<Button-3>", self.TreeMenu)
self.tree.hlist.bind("<MouseWheel>", self.Wheel)
- if (winsys == "x11"):
+ if (gui_winsys.winsys == "x11"):
self.tree.hlist.bind("<Button-4>", self.ButtonUp)
self.tree.hlist.bind("<Button-5>", self.ButtonDown)
pass
diff --git a/swig/python/openipmigui/gui_list.py b/swig/python/openipmigui/gui_list.py
index 18677c5..b8c5d72 100644
--- a/swig/python/openipmigui/gui_list.py
+++ b/swig/python/openipmigui/gui_list.py
@@ -32,7 +32,7 @@
import Tix
import gui_errstr
-import gui
+import gui_winsys
# A list widget that can be embedded in something else
class SubList(Tix.ScrolledHList):
@@ -55,7 +55,7 @@ class SubList(Tix.ScrolledHList):
self.bind("<Destroy>", self.OnDestroy)
self.hlist.bind("<MouseWheel>", self.Wheel)
- if (gui.winsys == "x11"):
+ if (gui_winsys.winsys == "x11"):
self.hlist.bind("<Button-4>", self.ButtonUp)
self.hlist.bind("<Button-5>", self.ButtonDown)
pass
diff --git a/swig/python/openipmigui/gui_treelist.py b/swig/python/openipmigui/gui_treelist.py
index 5d37ae2..7c4a45e 100644
--- a/swig/python/openipmigui/gui_treelist.py
+++ b/swig/python/openipmigui/gui_treelist.py
@@ -32,7 +32,7 @@
import Tix
import gui_errstr
-import gui
+import gui_winsys
class TreeList(Tix.Toplevel):
def __init__(self, name, root, columns):
@@ -84,7 +84,7 @@ class TreeList(Tix.Toplevel):
self.bind("<Destroy>", self.OnDestroy)
self.bind("<MouseWheel>", self.Wheel)
- if (gui.winsys == "x11"):
+ if (gui_winsys.winsys == "x11"):
self.bind("<Button-4>", self.ButtonUp)
self.bind("<Button-5>", self.ButtonDown)
pass
diff --git a/swig/python/openipmigui/gui_winsys.py b/swig/python/openipmigui/gui_winsys.py
new file mode 100644
index 0000000..a19b837
--- /dev/null
+++ b/swig/python/openipmigui/gui_winsys.py
@@ -0,0 +1,40 @@
+# gui.py
+#
+# main openipmi GUI handling
+#
+# Author: MontaVista Software, Inc.
+# Corey Minyard <minyard@mvista.com>
+# source@mvista.com
+#
+# Copyright 2005 MontaVista Software Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+#
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+try:
+ winsys = self.tk.eval("return [ tk windowingsystem ]")
+ pass
+except:
+ # Assume x11
+ winsys = "x11"
+ pass
+
diff --git a/tcl/Makefile.am b/tcl/Makefile.am
index b702819..e2a98dc 100644
--- a/tcl/Makefile.am
+++ b/tcl/Makefile.am
@@ -17,6 +17,7 @@ libOpenIPMItcl_la_LDFLAGS = -rdynamic -version-info $(LD_VERSION) \
noinst_PROGRAMS = test_handlers
test_handlers_SOURCES = test_handlers.c
+test_handlers_CFLAGS = $(TCL_CFLAGS) $(AM_CFLAGS)
test_handlers_LDADD = libOpenIPMItcl.la \
$(top_builddir)/utils/libOpenIPMIutils.la $(GDBM_LIB) $(TCL_LIBS)
diff --git a/unix/Makefile.am b/unix/Makefile.am
index a792147..ac5b9f4 100644
--- a/unix/Makefile.am
+++ b/unix/Makefile.am
@@ -2,7 +2,7 @@
LIB_VERSION = 0.0.1
LD_VERSION = 0:1:0
-AM_CFLAGS = -Wall -Wsign-compare -I$(top_builddir)/include \
+AM_CFLAGS = -lrt -Wall -Wsign-compare -I$(top_builddir)/include \
-I$(top_srcdir)/include
lib_LTLIBRARIES = libOpenIPMIposix.la libOpenIPMIpthread.la
diff --git a/unix/posix_thread_os_hnd.c b/unix/posix_thread_os_hnd.c
index 1110e01..a26fff8 100644
--- a/unix/posix_thread_os_hnd.c
+++ b/unix/posix_thread_os_hnd.c
@@ -392,11 +392,6 @@ sposix_log(os_handler_t *handler,
struct os_hnd_lock_s
{
pthread_mutex_t mutex;
- int lock_count;
-
- /* This is volatile and we always set the owner before we set the count.
- That avoids race conditions checking the count and owner. */
- volatile pthread_t owner;
};
static int
@@ -404,19 +399,30 @@ create_lock(os_handler_t *handler,
os_hnd_lock_t **id)
{
os_hnd_lock_t *lock;
+ pthread_mutexattr_t attr;
int rv;
lock = malloc(sizeof(*lock));
if (!lock)
return ENOMEM;
- rv = pthread_mutex_init(&lock->mutex, NULL);
- if (rv) {
- free(lock);
- return rv;
- }
- lock->lock_count = 0;
+ rv = pthread_mutexattr_init(&attr);
+ if (rv)
+ goto out_err;
+ rv = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ if (rv)
+ goto out_err_destroy;
+ rv = pthread_mutex_init(&lock->mutex, &attr);
+ if (rv)
+ goto out_err_destroy;
+ pthread_mutexattr_destroy(&attr);
*id = lock;
return 0;
+
+ out_err_destroy:
+ pthread_mutexattr_destroy(&attr);
+ out_err:
+ free(lock);
+ return rv;
}
static int
@@ -425,9 +431,6 @@ destroy_lock(os_handler_t *handler,
{
int rv;
- if (id->lock_count != 0)
- handler->log(handler, IPMI_LOG_FATAL,
- "Destroy of lock when count is not zero");
rv = pthread_mutex_destroy(&id->mutex);
if (rv)
return rv;
@@ -441,13 +444,9 @@ lock(os_handler_t *handler,
{
int rv;
- if ((id->lock_count == 0) || (pthread_self() != id->owner)) {
- rv = pthread_mutex_lock(&id->mutex);
- if (rv)
- return rv;
- }
- id->owner = pthread_self();
- id->lock_count++;
+ rv = pthread_mutex_lock(&id->mutex);
+ if (rv)
+ return rv;
return 0;
}
@@ -457,18 +456,9 @@ unlock(os_handler_t *handler,
{
int rv;
- if (id->lock_count == 0)
- handler->log(handler, IPMI_LOG_FATAL, "lock count went negative");
- if (pthread_self() != id->owner)
- handler->log(handler, IPMI_LOG_FATAL, "lock release by non-owner");
- id->lock_count--;
- if (id->lock_count == 0) {
- rv = pthread_mutex_unlock(&id->mutex);
- if (rv) {
- id->lock_count++;
- return rv;
- }
- }
+ rv = pthread_mutex_unlock(&id->mutex);
+ if (rv)
+ return rv;
return 0;
}
@@ -531,15 +521,8 @@ cond_wait(os_handler_t *handler,
os_hnd_lock_t *lock)
{
int rv;
- int old_lock_count;
- pthread_t old_owner;
- old_lock_count = lock->lock_count;
- old_owner = lock->owner;
- lock->lock_count = 0;
rv = pthread_cond_wait(&cond->cond, &lock->mutex);
- lock->lock_count = old_lock_count;
- lock->owner = old_owner;
return rv;
}
@@ -552,8 +535,6 @@ cond_timedwait(os_handler_t *handler,
struct timespec spec;
struct timeval now;
int rv;
- int old_lock_count;
- pthread_t old_owner;
rv = handler->get_monotonic_time(handler, &now);
if (rv)
@@ -565,12 +546,7 @@ cond_timedwait(os_handler_t *handler,
spec.tv_sec += 1;
spec.tv_nsec -= 1000000000;
}
- old_lock_count = lock->lock_count;
- old_owner = lock->owner;
- lock->lock_count = 0;
rv = pthread_cond_timedwait(&cond->cond, &lock->mutex, &spec);
- lock->lock_count = old_lock_count;
- lock->owner = old_owner;
return rv;
}