ipmievd.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. /*
  2. * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * Redistribution of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * Redistribution in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * Neither the name of Sun Microsystems, Inc. or the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * This software is provided "AS IS," without a warranty of any kind.
  20. * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
  21. * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
  22. * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
  23. * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
  24. * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  25. * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
  26. * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
  27. * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
  28. * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
  29. * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
  30. * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  31. */
  32. #define _XOPEN_SOURCE 700
  33. #define _BSD_SOURCE
  34. #include <stdio.h>
  35. #include <fcntl.h>
  36. #include <unistd.h>
  37. #include <sys/ioctl.h>
  38. #include <errno.h>
  39. #include <stdlib.h>
  40. #include <inttypes.h>
  41. #include <string.h>
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44. #include <signal.h>
  45. #if defined(HAVE_CONFIG_H)
  46. # include <config.h>
  47. #endif
  48. #if defined(HAVE_SYS_IOCCOM_H)
  49. # include <sys/ioccom.h>
  50. #endif
  51. #ifdef HAVE_PATHS_H
  52. # include <paths.h>
  53. #endif
  54. #ifndef _PATH_VARRUN
  55. # define _PATH_VARRUN "/var/run/"
  56. #endif
  57. #ifdef IPMI_INTF_OPEN
  58. # if defined(HAVE_OPENIPMI_H)
  59. # if defined(HAVE_LINUX_COMPILER_H)
  60. # include <linux/compiler.h>
  61. # endif
  62. # include <linux/ipmi.h>
  63. # elif defined(HAVE_FREEBSD_IPMI_H)
  64. # include <sys/ipmi.h>
  65. # else
  66. # include "plugins/open/open.h"
  67. # endif
  68. # include <poll.h>
  69. #endif /* IPMI_INTF_OPEN */
  70. #include <ipmitool/helper.h>
  71. #include <ipmitool/log.h>
  72. #include <ipmitool/ipmi.h>
  73. #include <ipmitool/ipmi_intf.h>
  74. #include <ipmitool/ipmi_sel.h>
  75. #include <ipmitool/ipmi_sdr.h>
  76. #include <ipmitool/ipmi_strings.h>
  77. #include <ipmitool/ipmi_main.h>
  78. #define WARNING_THRESHOLD 80
  79. #define DEFAULT_PIDFILE _PATH_VARRUN "ipmievd.pid"
  80. char pidfile[64];
  81. /* global variables */
  82. int verbose = 0;
  83. int csv_output = 0;
  84. uint16_t selwatch_count = 0; /* number of entries in the SEL */
  85. uint16_t selwatch_lastid = 0; /* current last entry in the SEL */
  86. int selwatch_pctused = 0; /* current percent usage in the SEL */
  87. int selwatch_overflow = 0; /* SEL overflow */
  88. int selwatch_timeout = 10; /* default to 10 seconds */
  89. /* event interface definition */
  90. struct ipmi_event_intf {
  91. char name[16];
  92. char desc[128];
  93. char prefix[72];
  94. int (*setup)(struct ipmi_event_intf * eintf);
  95. int (*wait)(struct ipmi_event_intf * eintf);
  96. int (*read)(struct ipmi_event_intf * eintf);
  97. int (*check)(struct ipmi_event_intf * eintf);
  98. void (*log)(struct ipmi_event_intf * eintf, struct sel_event_record * evt);
  99. struct ipmi_intf * intf;
  100. };
  101. /* Data from SEL we are interested in */
  102. typedef struct sel_data {
  103. uint16_t entries;
  104. int pctused;
  105. int overflow;
  106. } sel_data;
  107. static void log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt);
  108. /* ~~~~~~~~~~~~~~~~~~~~~~ openipmi ~~~~~~~~~~~~~~~~~~~~ */
  109. #ifdef IPMI_INTF_OPEN
  110. static int openipmi_setup(struct ipmi_event_intf * eintf);
  111. static int openipmi_wait(struct ipmi_event_intf * eintf);
  112. static int openipmi_read(struct ipmi_event_intf * eintf);
  113. static struct ipmi_event_intf openipmi_event_intf = {
  114. .name = "open",
  115. .desc = "OpenIPMI asyncronous notification of events",
  116. .prefix = "",
  117. .setup = openipmi_setup,
  118. .wait = openipmi_wait,
  119. .read = openipmi_read,
  120. .log = log_event,
  121. };
  122. #endif
  123. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  124. /* ~~~~~~~~~~~~~~~~~~~~~~ selwatch ~~~~~~~~~~~~~~~~~~~~ */
  125. static int selwatch_setup(struct ipmi_event_intf * eintf);
  126. static int selwatch_wait(struct ipmi_event_intf * eintf);
  127. static int selwatch_read(struct ipmi_event_intf * eintf);
  128. static int selwatch_check(struct ipmi_event_intf * eintf);
  129. static struct ipmi_event_intf selwatch_event_intf = {
  130. .name = "sel",
  131. .desc = "Poll SEL for notification of events",
  132. .setup = selwatch_setup,
  133. .wait = selwatch_wait,
  134. .read = selwatch_read,
  135. .check = selwatch_check,
  136. .log = log_event,
  137. };
  138. /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
  139. struct ipmi_event_intf * ipmi_event_intf_table[] = {
  140. #ifdef IPMI_INTF_OPEN
  141. &openipmi_event_intf,
  142. #endif
  143. &selwatch_event_intf,
  144. NULL
  145. };
  146. /*************************************************************************/
  147. static void
  148. ipmievd_usage(void)
  149. {
  150. lprintf(LOG_NOTICE, "Options:");
  151. lprintf(LOG_NOTICE, "\ttimeout=# Time between checks for SEL polling method [default=10]");
  152. lprintf(LOG_NOTICE, "\tdaemon Become a daemon [default]");
  153. lprintf(LOG_NOTICE, "\tnodaemon Do NOT become a daemon");
  154. }
  155. /* ipmi_intf_load - Load an event interface from the table above
  156. * If no interface name is given return first entry
  157. *
  158. * @name: interface name to try and load
  159. *
  160. * returns pointer to inteface structure if found
  161. * returns NULL on error
  162. */
  163. static struct ipmi_event_intf *
  164. ipmi_event_intf_load(char * name)
  165. {
  166. struct ipmi_event_intf ** intf;
  167. struct ipmi_event_intf * i;
  168. if (name == NULL) {
  169. i = ipmi_event_intf_table[0];
  170. return i;
  171. }
  172. for (intf = ipmi_event_intf_table;
  173. ((intf != NULL) && (*intf != NULL));
  174. intf++) {
  175. i = *intf;
  176. if (strncmp(name, i->name, strlen(name)) == 0) {
  177. return i;
  178. }
  179. }
  180. return NULL;
  181. }
  182. static int
  183. compute_pctfull(uint16_t entries, uint16_t freespace)
  184. {
  185. int pctfull = 0;
  186. if (entries) {
  187. entries *= 16;
  188. freespace += entries;
  189. pctfull = (int)(100 * ( (double)entries / (double)freespace ));
  190. }
  191. return pctfull;
  192. }
  193. static void
  194. log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt)
  195. {
  196. char *desc;
  197. const char *type;
  198. struct sdr_record_list * sdr;
  199. struct ipmi_intf * intf = eintf->intf;
  200. float trigger_reading = 0.0;
  201. float threshold_reading = 0.0;
  202. if (evt == NULL)
  203. return;
  204. if (evt->record_type == 0xf0) {
  205. lprintf(LOG_ALERT, "%sLinux kernel panic: %.11s",
  206. eintf->prefix, (char *) evt + 5);
  207. return;
  208. }
  209. else if (evt->record_type >= 0xc0) {
  210. lprintf(LOG_NOTICE, "%sIPMI Event OEM Record %02x",
  211. eintf->prefix, evt->record_type);
  212. return;
  213. }
  214. type = ipmi_get_sensor_type(intf, evt->sel_type.standard_type.sensor_type);
  215. ipmi_get_event_desc(intf, evt, &desc);
  216. sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt->sel_type.standard_type.gen_id, evt->sel_type.standard_type.sensor_num,
  217. evt->sel_type.standard_type.sensor_type);
  218. if (sdr == NULL) {
  219. /* could not find matching SDR record */
  220. if (desc) {
  221. lprintf(LOG_NOTICE, "%s%s sensor - %s",
  222. eintf->prefix, type, desc);
  223. free(desc);
  224. desc = NULL;
  225. } else {
  226. lprintf(LOG_NOTICE, "%s%s sensor %02x",
  227. eintf->prefix, type,
  228. evt->sel_type.standard_type.sensor_num);
  229. }
  230. return;
  231. }
  232. switch (sdr->type) {
  233. case SDR_RECORD_TYPE_FULL_SENSOR:
  234. if (evt->sel_type.standard_type.event_type == 1) {
  235. /*
  236. * Threshold Event
  237. */
  238. /* trigger reading in event data byte 2 */
  239. if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) {
  240. trigger_reading = sdr_convert_sensor_reading(
  241. sdr->record.full, evt->sel_type.standard_type.event_data[1]);
  242. }
  243. /* trigger threshold in event data byte 3 */
  244. if (((evt->sel_type.standard_type.event_data[0] >> 4) & 3) == 1) {
  245. threshold_reading = sdr_convert_sensor_reading(
  246. sdr->record.full, evt->sel_type.standard_type.event_data[2]);
  247. }
  248. lprintf(LOG_NOTICE, "%s%s sensor %s %s %s (Reading %.*f %s Threshold %.*f %s)",
  249. eintf->prefix,
  250. type,
  251. sdr->record.full->id_string,
  252. desc ? desc : "",
  253. (evt->sel_type.standard_type.event_dir
  254. ? "Deasserted" : "Asserted"),
  255. (trigger_reading==(int)trigger_reading) ? 0 : 2,
  256. trigger_reading,
  257. ((evt->sel_type.standard_type.event_data[0] & 0xf) % 2) ? ">" : "<",
  258. (threshold_reading==(int)threshold_reading) ? 0 : 2,
  259. threshold_reading,
  260. ipmi_sdr_get_unit_string(sdr->record.common->unit.pct,
  261. sdr->record.common->unit.modifier,
  262. sdr->record.common->unit.type.base,
  263. sdr->record.common->unit.type.modifier));
  264. }
  265. else if ((evt->sel_type.standard_type.event_type >= 0x2 && evt->sel_type.standard_type.event_type <= 0xc) ||
  266. (evt->sel_type.standard_type.event_type == 0x6f)) {
  267. /*
  268. * Discrete Event
  269. */
  270. lprintf(LOG_NOTICE, "%s%s sensor %s %s %s",
  271. eintf->prefix, type,
  272. sdr->record.full->id_string, desc ? desc : "",
  273. (evt->sel_type.standard_type.event_dir
  274. ? "Deasserted" : "Asserted"));
  275. if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) {
  276. /* previous state and/or severity in event data byte 2 */
  277. }
  278. }
  279. else if (evt->sel_type.standard_type.event_type >= 0x70 && evt->sel_type.standard_type.event_type <= 0x7f) {
  280. /*
  281. * OEM Event
  282. */
  283. lprintf(LOG_NOTICE, "%s%s sensor %s %s %s",
  284. eintf->prefix, type,
  285. sdr->record.full->id_string, desc ? desc : "",
  286. (evt->sel_type.standard_type.event_dir
  287. ? "Deasserted" : "Asserted"));
  288. }
  289. break;
  290. case SDR_RECORD_TYPE_COMPACT_SENSOR:
  291. lprintf(LOG_NOTICE, "%s%s sensor %s - %s %s",
  292. eintf->prefix, type,
  293. sdr->record.compact->id_string, desc ? desc : "",
  294. (evt->sel_type.standard_type.event_dir
  295. ? "Deasserted" : "Asserted"));
  296. break;
  297. default:
  298. lprintf(LOG_NOTICE, "%s%s sensor (0x%02x) - %s",
  299. eintf->prefix, type,
  300. evt->sel_type.standard_type.sensor_num, desc ? desc : "");
  301. break;
  302. }
  303. if (desc) {
  304. free(desc);
  305. desc = NULL;
  306. }
  307. }
  308. /*************************************************************************/
  309. /*************************************************************************/
  310. /** OpenIPMI Functions **/
  311. /*************************************************************************/
  312. #ifdef IPMI_INTF_OPEN
  313. static int
  314. openipmi_enable_event_msg_buffer(struct ipmi_intf * intf)
  315. {
  316. struct ipmi_rs * rsp;
  317. struct ipmi_rq req;
  318. uint8_t bmc_global_enables;
  319. /* we must read/modify/write bmc global enables */
  320. memset(&req, 0, sizeof(req));
  321. req.msg.netfn = IPMI_NETFN_APP;
  322. req.msg.cmd = 0x2f; /* Get BMC Global Enables */
  323. rsp = intf->sendrecv(intf, &req);
  324. if (rsp == NULL) {
  325. lprintf(LOG_ERR, "Get BMC Global Enables command failed");
  326. return -1;
  327. }
  328. else if (rsp->ccode > 0) {
  329. lprintf(LOG_ERR, "Get BMC Global Enables command failed: %s",
  330. val2str(rsp->ccode, completion_code_vals));
  331. return -1;
  332. }
  333. bmc_global_enables = rsp->data[0] | 0x04;
  334. req.msg.cmd = 0x2e; /* Set BMC Global Enables */
  335. req.msg.data = &bmc_global_enables;
  336. req.msg.data_len = 1;
  337. rsp = intf->sendrecv(intf, &req);
  338. if (rsp == NULL) {
  339. lprintf(LOG_ERR, "Set BMC Global Enables command failed");
  340. return -1;
  341. }
  342. else if (rsp->ccode > 0) {
  343. lprintf(LOG_ERR, "Set BMC Global Enables command failed: %s",
  344. val2str(rsp->ccode, completion_code_vals));
  345. return -1;
  346. }
  347. lprintf(LOG_DEBUG, "BMC Event Message Buffer enabled");
  348. return 0;
  349. }
  350. static int
  351. openipmi_setup(struct ipmi_event_intf * eintf)
  352. {
  353. int i, r;
  354. /* enable event message buffer */
  355. lprintf(LOG_DEBUG, "Enabling event message buffer");
  356. r = openipmi_enable_event_msg_buffer(eintf->intf);
  357. if (r < 0) {
  358. lprintf(LOG_ERR, "Could not enable event message buffer");
  359. return -1;
  360. }
  361. /* enable OpenIPMI event receiver */
  362. lprintf(LOG_DEBUG, "Enabling event receiver");
  363. i = 1;
  364. r = ioctl(eintf->intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i);
  365. if (r != 0) {
  366. lperror(LOG_ERR, "Could not enable event receiver");
  367. return -1;
  368. }
  369. return 0;
  370. }
  371. static int
  372. openipmi_read(struct ipmi_event_intf * eintf)
  373. {
  374. struct ipmi_addr addr;
  375. struct ipmi_recv recv;
  376. uint8_t data[80];
  377. int rv;
  378. recv.addr = (unsigned char *) &addr;
  379. recv.addr_len = sizeof(addr);
  380. recv.msg.data = data;
  381. recv.msg.data_len = sizeof(data);
  382. rv = ioctl(eintf->intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv);
  383. if (rv < 0) {
  384. switch (errno) {
  385. case EINTR:
  386. return 0; /* abort */
  387. case EMSGSIZE:
  388. recv.msg.data_len = sizeof(data); /* truncated */
  389. break;
  390. default:
  391. lperror(LOG_ERR, "Unable to receive IPMI message");
  392. return -1;
  393. }
  394. }
  395. if (!recv.msg.data || recv.msg.data_len == 0) {
  396. lprintf(LOG_ERR, "No data in event");
  397. return -1;
  398. }
  399. if (recv.recv_type != IPMI_ASYNC_EVENT_RECV_TYPE) {
  400. lprintf(LOG_ERR, "Type %x is not an event", recv.recv_type);
  401. return -1;
  402. }
  403. lprintf(LOG_DEBUG, "netfn:%x cmd:%x ccode:%d",
  404. recv.msg.netfn, recv.msg.cmd, recv.msg.data[0]);
  405. eintf->log(eintf, (struct sel_event_record *)recv.msg.data);
  406. return 0;
  407. }
  408. static int
  409. openipmi_wait(struct ipmi_event_intf * eintf)
  410. {
  411. struct pollfd pfd;
  412. int r;
  413. for (;;) {
  414. pfd.fd = eintf->intf->fd; /* wait on openipmi device */
  415. pfd.events = POLLIN; /* wait for input */
  416. r = poll(&pfd, 1, -1);
  417. switch (r) {
  418. case 0:
  419. /* timeout is disabled */
  420. break;
  421. case -1:
  422. lperror(LOG_CRIT, "Unable to read from IPMI device");
  423. return -1;
  424. default:
  425. if (pfd.revents & POLLIN)
  426. eintf->read(eintf);
  427. }
  428. }
  429. return 0;
  430. }
  431. #endif /* IPMI_INTF_OPEN */
  432. /*************************************************************************/
  433. /*************************************************************************/
  434. /** SEL Watch Functions **/
  435. /*************************************************************************/
  436. static int
  437. selwatch_get_data(struct ipmi_intf * intf, struct sel_data *data)
  438. {
  439. struct ipmi_rs * rsp;
  440. struct ipmi_rq req;
  441. uint16_t freespace;
  442. memset(&req, 0, sizeof(req));
  443. req.msg.netfn = IPMI_NETFN_STORAGE;
  444. req.msg.cmd = IPMI_CMD_GET_SEL_INFO;
  445. rsp = intf->sendrecv(intf, &req);
  446. if (rsp == NULL) {
  447. lprintf(LOG_ERR, "Get SEL Info command failed");
  448. return 0;
  449. }
  450. if (rsp->ccode > 0) {
  451. lprintf(LOG_ERR, "Get SEL Info command failed: %s",
  452. val2str(rsp->ccode, completion_code_vals));
  453. return 0;
  454. }
  455. freespace = buf2short(rsp->data + 3);
  456. data->entries = buf2short(rsp->data + 1);
  457. data->pctused = compute_pctfull (data->entries, freespace);
  458. data->overflow = rsp->data[13] & 0x80;
  459. lprintf(LOG_DEBUG, "SEL count is %d", data->entries);
  460. lprintf(LOG_DEBUG, "SEL freespace is %d", freespace);
  461. lprintf(LOG_DEBUG, "SEL Percent Used: %d%%\n", data->pctused);
  462. lprintf(LOG_DEBUG, "SEL Overflow: %s", data->overflow ? "true" : "false");
  463. return 1;
  464. }
  465. static uint16_t
  466. selwatch_get_lastid(struct ipmi_intf * intf)
  467. {
  468. int next_id = 0;
  469. uint16_t curr_id = 0;
  470. struct sel_event_record evt;
  471. if (selwatch_count == 0)
  472. return 0;
  473. while (next_id != 0xffff) {
  474. curr_id = next_id;
  475. lprintf(LOG_DEBUG, "SEL Next ID: %04x", curr_id);
  476. next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt);
  477. if (next_id < 0)
  478. break;
  479. if (next_id == 0) {
  480. /*
  481. * usually next_id of zero means end but
  482. * retry because some hardware has quirks
  483. * and will return 0 randomly.
  484. */
  485. next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt);
  486. if (next_id <= 0)
  487. break;
  488. }
  489. }
  490. lprintf(LOG_DEBUG, "SEL lastid is %04x", curr_id);
  491. return curr_id;
  492. }
  493. static int
  494. selwatch_setup(struct ipmi_event_intf * eintf)
  495. {
  496. struct sel_data data;
  497. /* save current sel record count */
  498. if (selwatch_get_data(eintf->intf, &data)) {
  499. selwatch_count = data.entries;
  500. selwatch_pctused = data.pctused;
  501. selwatch_overflow = data.overflow;
  502. lprintf(LOG_DEBUG, "Current SEL count is %d", selwatch_count);
  503. /* save current last record ID */
  504. selwatch_lastid = selwatch_get_lastid(eintf->intf);
  505. lprintf(LOG_DEBUG, "Current SEL lastid is %04x", selwatch_lastid);
  506. /* display alert/warning immediatly as startup if relevant */
  507. if (selwatch_pctused >= WARNING_THRESHOLD) {
  508. lprintf(LOG_WARNING, "SEL buffer used at %d%%, please consider clearing the SEL buffer", selwatch_pctused);
  509. }
  510. if (selwatch_overflow) {
  511. lprintf(LOG_ALERT, "SEL buffer overflow, no SEL message can be logged until the SEL buffer is cleared");
  512. }
  513. return 1;
  514. }
  515. lprintf(LOG_ERR, "Unable to retrieve SEL data");
  516. return 0;
  517. }
  518. /* selwatch_check - check for waiting events
  519. *
  520. * this is done by reading sel info and comparing
  521. * the sel count value to what we currently know
  522. */
  523. static int
  524. selwatch_check(struct ipmi_event_intf * eintf)
  525. {
  526. uint16_t old_count = selwatch_count;
  527. int old_pctused = selwatch_pctused;
  528. int old_overflow = selwatch_overflow;
  529. struct sel_data data;
  530. if (selwatch_get_data(eintf->intf, &data)) {
  531. selwatch_count = data.entries;
  532. selwatch_pctused = data.pctused;
  533. selwatch_overflow = data.overflow;
  534. if (old_overflow && !selwatch_overflow) {
  535. lprintf(LOG_NOTICE, "SEL overflow is cleared");
  536. } else if (!old_overflow && selwatch_overflow) {
  537. lprintf(LOG_ALERT, "SEL buffer overflow, no new SEL message will be logged until the SEL buffer is cleared");
  538. }
  539. if ((selwatch_pctused >= WARNING_THRESHOLD) && (selwatch_pctused > old_pctused)) {
  540. lprintf(LOG_WARNING, "SEL buffer is %d%% full, please consider clearing the SEL buffer", selwatch_pctused);
  541. }
  542. if (selwatch_count == 0) {
  543. lprintf(LOG_DEBUG, "SEL count is 0 (old=%d), resetting lastid to 0", old_count);
  544. selwatch_lastid = 0;
  545. } else if (selwatch_count < old_count) {
  546. selwatch_lastid = selwatch_get_lastid(eintf->intf);
  547. lprintf(LOG_DEBUG, "SEL count lowered, new SEL lastid is %04x", selwatch_lastid);
  548. }
  549. }
  550. return (selwatch_count > old_count);
  551. }
  552. static int
  553. selwatch_read(struct ipmi_event_intf * eintf)
  554. {
  555. uint16_t curr_id = 0;
  556. int next_id = selwatch_lastid;
  557. struct sel_event_record evt;
  558. if (selwatch_count == 0)
  559. return -1;
  560. while (next_id != 0xffff) {
  561. curr_id = next_id;
  562. lprintf(LOG_DEBUG, "SEL Read ID: %04x", curr_id);
  563. next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt);
  564. if (next_id < 0)
  565. break;
  566. if (next_id == 0) {
  567. /*
  568. * usually next_id of zero means end but
  569. * retry because some hardware has quirks
  570. * and will return 0 randomly.
  571. */
  572. next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt);
  573. if (next_id <= 0)
  574. break;
  575. }
  576. if (curr_id != selwatch_lastid)
  577. eintf->log(eintf, &evt);
  578. else if (curr_id == 0)
  579. eintf->log(eintf, &evt);
  580. }
  581. selwatch_lastid = curr_id;
  582. return 0;
  583. }
  584. static int
  585. selwatch_wait(struct ipmi_event_intf * eintf)
  586. {
  587. for (;;) {
  588. if (eintf->check(eintf) > 0) {
  589. lprintf(LOG_DEBUG, "New Events");
  590. eintf->read(eintf);
  591. }
  592. sleep(selwatch_timeout);
  593. }
  594. return 0;
  595. }
  596. /*************************************************************************/
  597. static void
  598. ipmievd_cleanup(int signal)
  599. {
  600. struct stat st1;
  601. if (lstat(pidfile, &st1) == 0) {
  602. /* cleanup daemon pidfile */
  603. (void)unlink(pidfile);
  604. }
  605. exit(EXIT_SUCCESS);
  606. }
  607. int
  608. ipmievd_main(struct ipmi_event_intf * eintf, int argc, char ** argv)
  609. {
  610. int i, rc;
  611. int daemon = 1;
  612. struct sigaction act;
  613. memset(pidfile, 0, 64);
  614. sprintf(pidfile, "%s%d", DEFAULT_PIDFILE, eintf->intf->devnum);
  615. for (i = 0; i < argc; i++) {
  616. if (strncasecmp(argv[i], "help", 4) == 0) {
  617. ipmievd_usage();
  618. return 0;
  619. }
  620. if (strncasecmp(argv[i], "daemon", 6) == 0) {
  621. daemon = 1;
  622. }
  623. else if (strncasecmp(argv[i], "nodaemon", 8) == 0) {
  624. daemon = 0;
  625. }
  626. else if (strncasecmp(argv[i], "daemon=", 7) == 0) {
  627. if (strncasecmp(argv[i]+7, "on", 2) == 0 ||
  628. strncasecmp(argv[i]+7, "yes", 3) == 0)
  629. daemon = 1;
  630. else if (strncasecmp(argv[i]+7, "off", 3) == 0 ||
  631. strncasecmp(argv[i]+7, "no", 2) == 0)
  632. daemon = 0;
  633. }
  634. else if (strncasecmp(argv[i], "timeout=", 8) == 0) {
  635. if ( (str2int(argv[i]+8, &selwatch_timeout) != 0) ||
  636. selwatch_timeout < 0) {
  637. lprintf(LOG_ERR, "Invalid input given or out of range for time-out.");
  638. return (-1);
  639. }
  640. }
  641. else if (strncasecmp(argv[i], "pidfile=", 8) == 0) {
  642. memset(pidfile, 0, 64);
  643. strncpy(pidfile, argv[i]+8,
  644. __min(strlen((const char *)(argv[i]+8)), 63));
  645. }
  646. }
  647. lprintf(LOG_DEBUG, "ipmievd: using pidfile %s", pidfile);
  648. /*
  649. * We need to open interface before forking daemon
  650. * so error messages are not lost to syslog and
  651. * return code is successfully returned to initscript
  652. */
  653. if (eintf->intf->open(eintf->intf) < 0) {
  654. lprintf(LOG_ERR, "Unable to open interface");
  655. return -1;
  656. }
  657. if (daemon) {
  658. FILE *fp;
  659. struct stat st1;
  660. if (lstat(pidfile, &st1) == 0) {
  661. /* PID file already exists -> exit. */
  662. lprintf(LOG_ERR, "PID file '%s' already exists.", pidfile);
  663. lprintf(LOG_ERR, "Perhaps another instance is already running.");
  664. return (-1);
  665. }
  666. ipmi_start_daemon(eintf->intf);
  667. umask(022);
  668. fp = ipmi_open_file_write(pidfile);
  669. if (fp == NULL) {
  670. /* Failed to get fp on PID file -> exit. */
  671. log_halt();
  672. log_init("ipmievd", daemon, verbose);
  673. lprintf(LOG_ERR,
  674. "Failed to open PID file '%s' for writing. Check file permission.",
  675. pidfile);
  676. exit(EXIT_FAILURE);
  677. }
  678. fprintf(fp, "%d\n", (int)getpid());
  679. fclose(fp);
  680. }
  681. /* register signal handler for cleanup */
  682. act.sa_handler = ipmievd_cleanup;
  683. act.sa_flags = 0;
  684. sigemptyset(&act.sa_mask);
  685. sigaction(SIGINT, &act, NULL);
  686. sigaction(SIGQUIT, &act, NULL);
  687. sigaction(SIGTERM, &act, NULL);
  688. log_halt();
  689. log_init("ipmievd", daemon, verbose);
  690. /* generate SDR cache for fast lookups */
  691. lprintf(LOG_NOTICE, "Reading sensors...");
  692. ipmi_sdr_list_cache(eintf->intf);
  693. lprintf(LOG_DEBUG, "Sensors cached");
  694. /* call event handler setup routine */
  695. if (eintf->setup != NULL) {
  696. rc = eintf->setup(eintf);
  697. if (rc < 0) {
  698. lprintf(LOG_ERR, "Error setting up Event Interface %s", eintf->name);
  699. return -1;
  700. }
  701. }
  702. lprintf(LOG_NOTICE, "Waiting for events...");
  703. /* now launch event wait loop */
  704. if (eintf->wait != NULL) {
  705. rc = eintf->wait(eintf);
  706. if (rc < 0) {
  707. lprintf(LOG_ERR, "Error waiting for events!");
  708. return -1;
  709. }
  710. }
  711. return 0;
  712. }
  713. int
  714. ipmievd_sel_main(struct ipmi_intf * intf, int argc, char ** argv)
  715. {
  716. struct ipmi_event_intf * eintf;
  717. eintf = ipmi_event_intf_load("sel");
  718. if (eintf == NULL) {
  719. lprintf(LOG_ERR, "Unable to load event interface");
  720. return -1;
  721. }
  722. eintf->intf = intf;
  723. if (intf->session != NULL) {
  724. snprintf(eintf->prefix,
  725. strlen((const char *)intf->ssn_params.hostname) + 3,
  726. "%s: ", intf->ssn_params.hostname);
  727. }
  728. return ipmievd_main(eintf, argc, argv);
  729. }
  730. int
  731. ipmievd_open_main(struct ipmi_intf * intf, int argc, char ** argv)
  732. {
  733. struct ipmi_event_intf * eintf;
  734. /* only one interface works for this */
  735. if (strncmp(intf->name, "open", 4) != 0) {
  736. lprintf(LOG_ERR, "Invalid Interface for OpenIPMI Event Handler: %s", intf->name);
  737. return -1;
  738. }
  739. eintf = ipmi_event_intf_load("open");
  740. if (eintf == NULL) {
  741. lprintf(LOG_ERR, "Unable to load event interface");
  742. return -1;
  743. }
  744. eintf->intf = intf;
  745. return ipmievd_main(eintf, argc, argv);
  746. }
  747. struct ipmi_cmd ipmievd_cmd_list[] = {
  748. #ifdef IPMI_INTF_OPEN
  749. { ipmievd_open_main, "open", "Use OpenIPMI for asyncronous notification of events" },
  750. #endif
  751. { ipmievd_sel_main, "sel", "Poll SEL for notification of events" },
  752. { NULL }
  753. };
  754. int main(int argc, char ** argv)
  755. {
  756. int rc;
  757. rc = ipmi_main(argc, argv, ipmievd_cmd_list, NULL);
  758. if (rc < 0)
  759. exit(EXIT_FAILURE);
  760. else
  761. exit(EXIT_SUCCESS);
  762. }