Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:42.3:Staging:D
OpenIPMI
OpenIPMI_2.0.21_to_HEAD.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File OpenIPMI_2.0.21_to_HEAD.patch of Package OpenIPMI
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; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor