static void _daemon_cmd_err (const char *str, int exit_on_fatal) { assert (str); if (!cmd_args.verbose_logging) { if (repeat_ipmi_ctx_errnum == last_ipmi_ctx_errnum && repeat_cmd == last_cmd && repeat_netfn == last_netfn && repeat_comp_code == last_comp_code) { log_repeat_count++; if (log_repeat_count < BMC_WATCHDOG_LOG_REPEAT_LIMIT) return; } } if (ipmi_ctx_errnum (ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE) err_output ("%s: %s", str, comp_code_errbuf); else if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_DRIVER_BUSY && ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BMC_BUSY && ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_IPMI_ERROR) { err_output ("%s: %s", str, ipmi_ctx_errormsg (ipmi_ctx)); if (exit_on_fatal) exit (EXIT_FAILURE); } repeat_ipmi_ctx_errnum = last_ipmi_ctx_errnum; repeat_cmd = last_cmd; repeat_netfn = last_netfn; repeat_comp_code = last_comp_code; log_repeat_count = 0; }
static void log_no_err(const char *fmt,...) { #ifdef AP_LOG_EXEC va_list ap; va_start(ap, fmt); err_output(0, fmt, ap); /* 0 == !is_error */ va_end(ap); #endif /* AP_LOG_EXEC */ return; }
static void log_err(const char *fmt,...) { #ifdef LOG_EXEC va_list ap; va_start(ap, fmt); err_output(fmt, ap); va_end(ap); #endif /* LOG_EXEC */ return; }
static void log_err(const char *fmt,...) { #ifdef SUEXEC_LOGFILE va_list ap; va_start(ap, fmt); err_output(1, fmt, ap); /* 1 == is_error */ va_end(ap); #endif /* SUEXEC_LOGFILE */ return; }
void ipmiseld_err_output (ipmiseld_host_data_t *host_data, const char *message, ...) { char buf[IPMISELD_ERR_BUFLEN + 1]; va_list ap; assert (host_data); assert (message); memset (buf, '\0', IPMISELD_ERR_BUFLEN + 1); va_start (ap, message); vsnprintf(buf, IPMISELD_ERR_BUFLEN, message, ap); if (!host_data->hostname) err_output ("%s", buf); else err_output ("%s: %s", host_data->hostname, buf); va_end (ap); }
static void _config_file_parse (void) { int ipmiping_period_flag, ipmidetectd_server_port_flag, host_flag; struct conffile_option options[] = { { "ipmiping_period", CONFFILE_OPTION_INT, -1, conffile_int, 1, 0, &(ipmiping_period_flag), &(conf.ipmiping_period), 0 }, { "ipmidetectd_server_port", CONFFILE_OPTION_INT, -1, conffile_int, 1, 0, &(ipmidetectd_server_port_flag), &(conf.ipmidetectd_server_port), 0, }, { "host", CONFFILE_OPTION_STRING, -1, _cb_host, INT_MAX, 0, &host_flag, NULL, 0 }, }; conffile_t cf = NULL; int legacy_file_loaded = 0; int num; if (!(cf = conffile_handle_create ())) { err_output ("conffile_handle_create"); goto cleanup; } num = sizeof (options)/sizeof (struct conffile_option); /* Try legacy file first */ if (!cmd_args.config_file) { if (!conffile_parse (cf, IPMIDETECTD_CONFIG_FILE_LEGACY, options, num, NULL, 0, 0)) legacy_file_loaded++; } if (!legacy_file_loaded) { if (conffile_parse (cf, cmd_args.config_file ? cmd_args.config_file : IPMIDETECTD_CONFIG_FILE_DEFAULT, options, num, NULL, 0, 0) < 0) { char buf[CONFFILE_MAX_ERRMSGLEN]; /* Its not an error if the default configuration file doesn't exist */ if ((!cmd_args.config_file || !strcmp (cmd_args.config_file, IPMIDETECTD_CONFIG_FILE_DEFAULT)) && conffile_errnum (cf) == CONFFILE_ERR_EXIST) goto cleanup; if (conffile_errmsg (cf, buf, CONFFILE_MAX_ERRMSGLEN) < 0) err_exit ("conffile_parse: %d", conffile_errnum (cf)); else err_exit ("conffile_parse: %s", buf); } } cleanup: conffile_handle_destroy (cf); }
static int _cmd (const char *str, uint8_t netfn, uint8_t cmd, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { int retry_count = 0; int ret = 0; assert (str && (netfn == IPMI_NET_FN_APP_RQ || netfn == IPMI_NET_FN_TRANSPORT_RQ) && obj_cmd_rq && obj_cmd_rs); last_ipmi_ctx_errnum = -1; last_cmd = cmd; last_netfn = netfn; last_comp_code = 0; while (1) { if ((ret = ipmi_cmd (ipmi_ctx, IPMI_BMC_IPMB_LUN_BMC, netfn, obj_cmd_rq, obj_cmd_rs)) < 0) { last_ipmi_ctx_errnum = ipmi_ctx_errnum (ipmi_ctx); if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_DRIVER_BUSY && ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BMC_BUSY && ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_IPMI_ERROR) { if (cmd_args.verbose_logging) err_output ("%s: ipmi_cmd: %s", str, ipmi_ctx_errormsg (ipmi_ctx)); if (ipmi_ctx_errnum (ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE) { if (ipmi_completion_code_strerror_cmd_r (obj_cmd_rs, netfn, comp_code_errbuf, BMC_WATCHDOG_ERR_BUFLEN) < 0) { uint64_t val; _fiid_obj_get (obj_cmd_rs, "comp_code", &val); last_comp_code = val; snprintf (comp_code_errbuf, BMC_WATCHDOG_ERR_BUFLEN, "Comp Code 0x%X", last_comp_code); } } return (-1); } } if (ret < 0) { if (retry_count >= retry_attempts) { err_output ("%s: BMC Timeout: %s", str, ipmi_ctx_errormsg (ipmi_ctx)); return (-1); } daemon_sleep (retry_wait_time); retry_count++; } else break; } return (0); }
static void _daemon_cmd (const char *progname) { uint32_t reset_period = BMC_WATCHDOG_RESET_PERIOD_DEFAULT; uint8_t timer_use, timer_state, log, timeout_action, pre_timeout_interrupt, pre_timeout_interval; uint16_t initial_countdown_seconds; uint16_t previous_present_countdown_seconds = 0; uint16_t present_countdown_seconds; assert (progname); /* Run in foreground if debugging */ if (!cmd_args.common_args.debug) daemonize_common (BMC_WATCHDOG_PIDFILE); daemon_signal_handler_setup (_signal_handler_callback); /* move error outs to syslog from stderr */ if (!cmd_args.no_logging) err_set_flags (ERROR_SYSLOG); else err_set_flags (0); openlog (progname, LOG_ODELAY | LOG_PID, LOG_DAEMON); _init_bmc_watchdog (); _daemon_setup (); if (cmd_args.reset_period) reset_period = cmd_args.reset_period_arg; retry_wait_time = BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT; retry_attempts = BMC_WATCHDOG_RETRY_ATTEMPTS_DEFAULT; if ((retry_wait_time * retry_attempts) > reset_period) { retry_wait_time = 0; retry_attempts = 0; } else if (reset_period > retry_wait_time && reset_period < (retry_wait_time * retry_attempts)) retry_attempts = reset_period/retry_wait_time; /* IPMI Workaround * * Discovered on Sun x4100M2 and x4200M2 * * If implementing the IGNORE_STATE_FLAG workaround flag below, we * need to sleep a little bit to make sure the BMC timer has really * started. * * From 27.7 "Internal delays in the BMC may require software to * delay up to 100 ms before seeing the countdown value change and * be reflected in the Get Watchdog Timer command". */ if (cmd_args.common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IGNORE_STATE_FLAG) daemon_sleep (1); while (shutdown_flag) { struct timeval start_tv, end_tv; uint32_t adjusted_period; if (gettimeofday (&start_tv, NULL) < 0) err_exit ("gettimeofday: %s", strerror (errno)); if (_get_watchdog_timer_cmd (NULL, &timer_state, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &present_countdown_seconds) < 0) { _daemon_cmd_err_no_exit ("Get Watchdog Timer"); goto sleep_now; } /* IPMI Workaround * * Discovered on Sun x4100M2 and x4200M2 * * On some BMCs, the timer state flag is not functional. Therefore, * to have an operational BMC watchdog, it must function without it. * We instead look to see if the timer is changing. */ if (cmd_args.common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IGNORE_STATE_FLAG) { if (previous_present_countdown_seconds == present_countdown_seconds) { err_output ("timer stopped by another process"); return; } previous_present_countdown_seconds = present_countdown_seconds; } else { if (timer_state == IPMI_BMC_WATCHDOG_TIMER_TIMER_STATE_STOPPED) { err_output ("timer stopped by another process"); return; } } if (_reset_watchdog_timer_cmd () < 0) { _daemon_cmd_err_no_exit ("Reset Watchdog Timer"); goto sleep_now; } /* IPMI Workaround * * Discovered on Sun x4100M2 and x4200M2 * * If implementing the IGNORE_STATE_FLAG workaround flag above, * we need to reset the previous_present_countdown_seconds to * what it is after the timer reset. */ if (cmd_args.common_args.section_specific_workaround_flags & IPMI_PARSE_SECTION_SPECIFIC_WORKAROUND_FLAGS_IGNORE_STATE_FLAG) { /* From 27.7 "Internal delays in the BMC may require software to * delay up to 100 ms before seeing the countdown value change and * be reflected in the Get Watchdog Timer command". */ daemon_sleep (1); if (_get_watchdog_timer_cmd (NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &present_countdown_seconds) < 0) { _daemon_cmd_err_no_exit ("Get Watchdog Timer"); goto sleep_now; } previous_present_countdown_seconds = present_countdown_seconds; } sleep_now: if (gettimeofday (&end_tv, NULL) < 0) err_exit ("gettimeofday: %s", strerror (errno)); adjusted_period = reset_period; /* Ignore micro secs, just seconds is good enough */ if ((end_tv.tv_sec - start_tv.tv_sec) < adjusted_period) adjusted_period -= (end_tv.tv_sec - start_tv.tv_sec); daemon_sleep (adjusted_period); } /* Need to stop the timer, don't want it to keep on going. Don't * give up until its shut off. */ /* set back to defaults, no reset-period adjustment anymore */ retry_wait_time = BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT; retry_attempts = BMC_WATCHDOG_RETRY_ATTEMPTS_DEFAULT; while (1) { if (_get_watchdog_timer_cmd (&timer_use, NULL, &log, &timeout_action, &pre_timeout_interrupt, &pre_timeout_interval, NULL, NULL, NULL, NULL, NULL, &initial_countdown_seconds, NULL) < 0) { _daemon_cmd_err_no_exit ("Get Watchdog Timer"); daemon_sleep (BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT); continue; } break; } while (1) { if (_set_watchdog_timer_cmd (timer_use, IPMI_BMC_WATCHDOG_TIMER_STOP_TIMER_ENABLE, log, timeout_action, pre_timeout_interrupt, pre_timeout_interval, 0, 0, 0, 0, 0, initial_countdown_seconds) < 0) { _daemon_cmd_err_no_exit ("Set Watchdog Timer"); daemon_sleep (BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT); continue; } break; } }
static void _daemon_setup (void) { uint8_t timer_use, timer_state, log, timeout_action, pre_timeout_interrupt, pre_timeout_interval; uint32_t reset_period = BMC_WATCHDOG_RESET_PERIOD_DEFAULT; uint16_t initial_countdown_seconds; while (1) { if (_get_watchdog_timer_cmd (&timer_use, &timer_state, &log, &timeout_action, &pre_timeout_interrupt, &pre_timeout_interval, NULL, NULL, NULL, NULL, NULL, &initial_countdown_seconds, NULL) < 0) { _daemon_cmd_err_maybe_exit ("Get Watchdog Timer"); daemon_sleep (BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT); continue; } break; } if (timer_state == IPMI_BMC_WATCHDOG_TIMER_TIMER_STATE_RUNNING) err_exit ("Error: watchdog timer must be stopped before running daemon"); timer_use = (cmd_args.timer_use) ? cmd_args.timer_use_arg : timer_use; log = (cmd_args.log) ? cmd_args.log_arg : log; timeout_action = (cmd_args.timeout_action) ? cmd_args.timeout_action_arg : timeout_action; pre_timeout_interrupt = (cmd_args.pre_timeout_interrupt) ? cmd_args.pre_timeout_interrupt_arg : pre_timeout_interrupt; pre_timeout_interval = (cmd_args.pre_timeout_interval) ? cmd_args.pre_timeout_interval_arg : pre_timeout_interval; initial_countdown_seconds = (cmd_args.initial_countdown_seconds) ? cmd_args.initial_countdown_seconds_arg : initial_countdown_seconds; if ((pre_timeout_interrupt != IPMI_BMC_WATCHDOG_TIMER_PRE_TIMEOUT_INTERRUPT_NONE) && (pre_timeout_interval > initial_countdown_seconds)) err_exit ("Error: pre-timeout interval greater than initial countdown seconds"); if (cmd_args.reset_period) reset_period = cmd_args.reset_period_arg; if (reset_period > initial_countdown_seconds) err_exit ("Error: reset-period interval greater than initial countdown seconds"); while (1) { if (_set_watchdog_timer_cmd (timer_use, IPMI_BMC_WATCHDOG_TIMER_STOP_TIMER_ENABLE, log, timeout_action, pre_timeout_interrupt, pre_timeout_interval, (cmd_args.clear_bios_frb2) ? 1 : 0, (cmd_args.clear_bios_post) ? 1 : 0, (cmd_args.clear_os_load) ? 1 : 0, (cmd_args.clear_sms_os) ? 1 : 0, (cmd_args.clear_oem) ? 1 : 0, initial_countdown_seconds) < 0) { _daemon_cmd_err_maybe_exit ("Set Watchdog Timer"); daemon_sleep (BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT); continue; } break; } /* Must start watchdog timer before entering loop */ while (1) { if (_reset_watchdog_timer_cmd () < 0) { _daemon_cmd_err_maybe_exit ("Reset Watchdog Timer"); daemon_sleep (BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT); continue; } break; } if (cmd_args.gratuitous_arp || cmd_args.arp_response) { uint8_t gratuitous_arp, arp_response; if (cmd_args.gratuitous_arp) gratuitous_arp = cmd_args.gratuitous_arp_arg; else gratuitous_arp = IPMI_BMC_GENERATED_GRATUITOUS_ARP_DO_NOT_SUSPEND; if (cmd_args.arp_response) arp_response = cmd_args.gratuitous_arp_arg; else arp_response = IPMI_BMC_GENERATED_ARP_RESPONSE_DO_NOT_SUSPEND; while (1) { int ret; if ((ret = _suspend_bmc_arps_cmd (gratuitous_arp, arp_response)) < 0) { _daemon_cmd_err_maybe_exit ("Suspend BMC ARPs"); daemon_sleep (BMC_WATCHDOG_RETRY_WAIT_TIME_DEFAULT); continue; } if (!ret) err_output ("cannot suspend BMC ARPs"); break; } } return; }