1 /*
2 * test1.c
3 *
4 * OpenIPMI test code showing event setup
5 *
6 * Author: Corey Minyard <minyard@acm.org>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 *
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
20 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this program; if not, write to the Free
27 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <ctype.h>
39 #include <time.h>
40
41 #include <OpenIPMI/ipmiif.h>
42 #include <OpenIPMI/ipmi_smi.h>
43 #include <OpenIPMI/ipmi_err.h>
44 #include <OpenIPMI/ipmi_auth.h>
45 #include <OpenIPMI/ipmi_lan.h>
46 #include <OpenIPMI/ipmi_posix.h>
47
48 /* This sample application demostrates some general handling of sensors,
49 like reading values, setting up events, and things of that nature.
50 It also demonstrates some good coding practices like refcounting
51 structures. */
52
53 static const char *progname;
54
55 #define MAX_SENSOR_NAME_SIZE 128
56
57 typedef struct sdata_s
58 {
59 unsigned int refcount;
60 ipmi_sensor_id_t sensor_id;
61 char name[MAX_SENSOR_NAME_SIZE];
62 ipmi_event_state_t *es;
63 ipmi_thresholds_t *th;
64 int state_sup;
65 int thresh_sup;
66
67 struct sdata_s *next, *prev;
68 } sdata_t;
69
70 static sdata_t *sdata_list = NULL;
71
72 static sdata_t *
alloc_sdata(ipmi_sensor_t * sensor)73 alloc_sdata(ipmi_sensor_t *sensor)
74 {
75 sdata_t *sdata;
76
77 sdata = malloc(sizeof(*sdata));
78 if (!sdata)
79 return NULL;
80
81 sdata->es = malloc(ipmi_event_state_size());
82 if (!sdata->es) {
83 free(sdata);
84 return NULL;
85 }
86 ipmi_event_state_init(sdata->es);
87
88 sdata->th = malloc(ipmi_thresholds_size());
89 if (!sdata->th) {
90 free(sdata->es);
91 free(sdata);
92 return NULL;
93 }
94 ipmi_thresholds_init(sdata->th);
95
96 sdata->refcount = 1;
97
98 sdata->sensor_id = ipmi_sensor_convert_to_id(sensor);
99 ipmi_sensor_get_name(sensor, sdata->name, sizeof(sdata->name));
100
101 sdata->next = sdata_list;
102 sdata->prev = NULL;
103 sdata_list = sdata;
104
105 return sdata;
106 }
107
108 static sdata_t *
find_sdata(ipmi_sensor_t * sensor)109 find_sdata(ipmi_sensor_t *sensor)
110 {
111 ipmi_sensor_id_t id = ipmi_sensor_convert_to_id(sensor);
112 sdata_t *link;
113
114 link = sdata_list;
115 while (link) {
116 if (ipmi_cmp_sensor_id(id, link->sensor_id) == 0)
117 return link;
118 link = link->next;
119 }
120 return NULL;
121 }
122
123 static void
use_sdata(sdata_t * sdata)124 use_sdata(sdata_t *sdata)
125 {
126 sdata->refcount++;
127 }
128
129 static void
release_sdata(sdata_t * sdata)130 release_sdata(sdata_t *sdata)
131 {
132 sdata->refcount--;
133 if (sdata->refcount == 0) {
134 /* Remove it from the list. */
135 if (sdata->next)
136 sdata->next->prev = sdata->prev;
137
138 if (sdata->prev)
139 sdata->prev->next = sdata->next;
140 else
141 sdata_list = sdata->next;
142
143 free(sdata->es);
144 free(sdata->th);
145 free(sdata);
146 }
147 }
148
con_usage(const char * name,const char * help,void * cb_data)149 static void con_usage(const char *name, const char *help, void *cb_data)
150 {
151 printf("\n%s%s", name, help);
152 }
153
154 static void
usage(void)155 usage(void)
156 {
157 printf("Usage:\n");
158 printf(" %s <con_parms>\n", progname);
159 printf(" Where <con_parms> is one of:");
160 ipmi_parse_args_iter_help(con_usage, NULL);
161 }
162
163 static void
got_thresh_reading(ipmi_sensor_t * sensor,int err,enum ipmi_value_present_e value_present,unsigned int raw_value,double val,ipmi_states_t * states,void * cb_data)164 got_thresh_reading(ipmi_sensor_t *sensor,
165 int err,
166 enum ipmi_value_present_e value_present,
167 unsigned int raw_value,
168 double val,
169 ipmi_states_t *states,
170 void *cb_data)
171 {
172 sdata_t *sdata = cb_data;
173 enum ipmi_thresh_e thresh;
174
175 if (err) {
176 printf("Error 0x%x getting discrete states for sensor %s\n",
177 err, sdata->name);
178 goto out;
179 }
180
181 printf("Got threshold reading for sensor %s\n", sdata->name);
182 if (ipmi_is_event_messages_enabled(states))
183 printf(" event messages enabled\n");
184 if (ipmi_is_sensor_scanning_enabled(states))
185 printf(" sensor scanning enabled\n");
186 if (ipmi_is_initial_update_in_progress(states))
187 printf(" initial update in progress\n");
188
189 switch (value_present)
190 {
191 case IPMI_NO_VALUES_PRESENT:
192 printf(" no value present\n");
193 break;
194 case IPMI_BOTH_VALUES_PRESENT:
195 {
196 const char *percent = "";
197 const char *base;
198 const char *mod_use = "";
199 const char *modifier = "";
200 const char *rate;
201
202 base = ipmi_sensor_get_base_unit_string(sensor);
203 if (ipmi_sensor_get_percentage(sensor))
204 percent = "%";
205 switch (ipmi_sensor_get_modifier_unit_use(sensor)) {
206 case IPMI_MODIFIER_UNIT_NONE:
207 break;
208 case IPMI_MODIFIER_UNIT_BASE_DIV_MOD:
209 mod_use = "/";
210 modifier = ipmi_sensor_get_modifier_unit_string(sensor);
211 break;
212 case IPMI_MODIFIER_UNIT_BASE_MULT_MOD:
213 mod_use = "*";
214 modifier = ipmi_sensor_get_modifier_unit_string(sensor);
215 break;
216 }
217 rate = ipmi_sensor_get_rate_unit_string(sensor);
218
219 printf(" value: %lf%s %s%s%s%s\n", val, percent,
220 base, mod_use, modifier, rate);
221 }
222 /* FALLTHROUGH */
223 case IPMI_RAW_VALUE_PRESENT:
224 printf(" raw value: 0x%2.2x\n", raw_value);
225 }
226
227 if (sdata->thresh_sup == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE)
228 goto out;
229
230 for (thresh=IPMI_LOWER_NON_CRITICAL;
231 thresh<=IPMI_UPPER_NON_RECOVERABLE;
232 thresh++)
233 {
234 int val, rv;
235
236 rv = ipmi_sensor_threshold_reading_supported(sensor, thresh, &val);
237 if (rv || !val)
238 continue;
239
240 if (ipmi_is_threshold_out_of_range(states, thresh))
241 printf(" Threshold %s is out of range\n",
242 ipmi_get_threshold_string(thresh));
243 else
244 printf(" Threshold %s is in range\n",
245 ipmi_get_threshold_string(thresh));
246 }
247
248 out:
249 release_sdata(sdata);
250 }
251
252 static void
got_discrete_states(ipmi_sensor_t * sensor,int err,ipmi_states_t * states,void * cb_data)253 got_discrete_states(ipmi_sensor_t *sensor,
254 int err,
255 ipmi_states_t *states,
256 void *cb_data)
257 {
258 sdata_t *sdata = cb_data;
259 int i;
260
261 if (err) {
262 printf("Error 0x%x getting discrete states for sensor %s\n",
263 err, sdata->name);
264 goto out;
265 }
266
267 if (err) {
268 printf("Error 0x%x getting discrete states for sensor %s\n",
269 err, sdata->name);
270 goto out;
271 }
272
273 printf("Got state reading for sensor %s\n", sdata->name);
274 if (ipmi_is_event_messages_enabled(states))
275 printf(" event messages enabled\n");
276 if (ipmi_is_sensor_scanning_enabled(states))
277 printf(" sensor scanning enabled\n");
278 if (ipmi_is_initial_update_in_progress(states))
279 printf(" initial update in progress\n");
280
281 for (i=0; i<15; i++) {
282 int val, rv;
283
284 rv = ipmi_sensor_discrete_event_readable(sensor, i, &val);
285 if (rv || !val)
286 continue;
287
288 printf(" state %d value is %d\n", i, ipmi_is_state_set(states, i));
289 }
290
291 out:
292 release_sdata(sdata);
293 }
294
295 static void
event_set_done(ipmi_sensor_t * sensor,int err,void * cb_data)296 event_set_done(ipmi_sensor_t *sensor,
297 int err,
298 void *cb_data)
299 {
300 sdata_t *sdata = cb_data;
301
302 if (err) {
303 printf("Error 0x%x setting events for sensor %s\n", err, sdata->name);
304 goto out;
305 }
306
307 printf("Events set for sensor %s\n", sdata->name);
308
309 out:
310 release_sdata(sdata);
311 }
312
313 static void
got_events(ipmi_sensor_t * sensor,int err,ipmi_event_state_t * states,void * cb_data)314 got_events(ipmi_sensor_t *sensor,
315 int err,
316 ipmi_event_state_t *states,
317 void *cb_data)
318 {
319 sdata_t *sdata = cb_data;
320 int rv;
321
322 if (err) {
323 printf("Error 0x%x getting events for sensor %s\n", err, sdata->name);
324 goto out_err;
325 }
326
327 /* Turn on the general events for a sensor, since this at
328 least supports per-sensor enables. */
329 ipmi_event_state_set_events_enabled(sdata->es, 1);
330 ipmi_event_state_set_scanning_enabled(sdata->es, 1);
331
332 printf("Sensor %s event settings:\n", sdata->name);
333 if (sdata->state_sup != IPMI_EVENT_SUPPORT_PER_STATE) {
334 /* No per-state sensors, just do the global enable. */
335 } else if (ipmi_sensor_get_event_reading_type(sensor)
336 == IPMI_EVENT_READING_TYPE_THRESHOLD)
337 {
338 /* Check each event, print out the current state, and turn it
339 on in the events to set if it is available. */
340 enum ipmi_event_value_dir_e value_dir;
341 enum ipmi_event_dir_e dir;
342 enum ipmi_thresh_e thresh;
343 int val;
344 for (value_dir=IPMI_GOING_LOW; value_dir<=IPMI_GOING_HIGH; value_dir++)
345 {
346 for (dir=IPMI_ASSERTION; dir<=IPMI_DEASSERTION; dir++) {
347 for (thresh=IPMI_LOWER_NON_CRITICAL;
348 thresh<=IPMI_UPPER_NON_RECOVERABLE;
349 thresh++)
350 {
351 char *v;
352
353 rv = ipmi_sensor_threshold_event_supported
354 (sensor, thresh, value_dir, dir, &val);
355 if (rv || !val)
356 continue;
357
358 if (ipmi_is_threshold_event_set(states, thresh,
359 value_dir, dir))
360 v = "";
361 else
362 v = " not";
363
364 printf(" %s %s %s was%s enabled\n",
365 ipmi_get_threshold_string(thresh),
366 ipmi_get_value_dir_string(value_dir),
367 ipmi_get_event_dir_string(dir),
368 v);
369
370 ipmi_threshold_event_set(sdata->es, thresh,
371 value_dir, dir);
372 }
373 }
374 }
375 } else {
376 /* Check each event, print out the current state, and turn it
377 on in the events to set if it is available. */
378 enum ipmi_event_dir_e dir;
379 int i;
380
381 for (dir=IPMI_ASSERTION; dir<=IPMI_DEASSERTION; dir++) {
382 for (i=0; i<15; i++) {
383 char *v;
384 int val;
385
386 rv = ipmi_sensor_discrete_event_supported
387 (sensor, i, dir, &val);
388 if (rv || !val)
389 continue;
390
391 if (ipmi_is_discrete_event_set(states, i, dir))
392 v = "";
393 else
394 v = " not";
395
396 printf(" bit %d %s was%s enabled\n",
397 i,
398 ipmi_get_event_dir_string(dir),
399 v);
400
401 ipmi_discrete_event_set(sdata->es, i, dir);
402 }
403 }
404 }
405
406 rv = ipmi_sensor_set_event_enables(sensor, sdata->es,
407 event_set_done, sdata);
408 if (rv) {
409 printf("Error 0x%x enabling events for sensor %s\n", err, sdata->name);
410 goto out_err;
411 }
412
413 return;
414
415 out_err:
416 release_sdata(sdata);
417 }
418
419 static void
thresholds_set(ipmi_sensor_t * sensor,int err,void * cb_data)420 thresholds_set(ipmi_sensor_t *sensor, int err, void *cb_data)
421 {
422 sdata_t *sdata = cb_data;
423
424 if (err) {
425 printf("Error 0x%x setting thresholds for sensor %s\n",
426 err, sdata->name);
427 goto out;
428 }
429
430 printf("Thresholds set for sensor %s\n", sdata->name);
431
432 out:
433 release_sdata(sdata);
434 }
435
436 static void
got_thresholds(ipmi_sensor_t * sensor,int err,ipmi_thresholds_t * th,void * cb_data)437 got_thresholds(ipmi_sensor_t *sensor,
438 int err,
439 ipmi_thresholds_t *th,
440 void *cb_data)
441 {
442 sdata_t *sdata = cb_data;
443 enum ipmi_thresh_e thresh;
444 int rv;
445
446 if (err) {
447 printf("Error 0x%x getting events for sensor %s\n", err, sdata->name);
448 goto out_err;
449 }
450
451 printf("Sensor %s threshold settings:\n", sdata->name);
452 for (thresh=IPMI_LOWER_NON_CRITICAL;
453 thresh<=IPMI_UPPER_NON_RECOVERABLE;
454 thresh++)
455 {
456 int val;
457 double dval;
458
459 rv = ipmi_sensor_threshold_readable(sensor, thresh, &val);
460 if (rv || !val)
461 /* Threshold not available. */
462 continue;
463
464 rv = ipmi_threshold_get(th, thresh, &dval);
465 if (rv) {
466 printf(" threshold %s could not be fetched due to error 0x%x\n",
467 ipmi_get_threshold_string(thresh), rv);
468 } else {
469 printf(" threshold %s is %lf\n",
470 ipmi_get_threshold_string(thresh), dval);
471 }
472 }
473
474 rv = ipmi_get_default_sensor_thresholds(sensor, sdata->th);
475 if (rv) {
476 printf("Error 0x%x getting def thresholds for sensor %s\n",
477 rv, sdata->name);
478 goto out_err;
479 }
480
481 rv = ipmi_sensor_set_thresholds(sensor, sdata->th, thresholds_set, sdata);
482 if (rv) {
483 printf("Error 0x%x setting thresholds for sensor %s\n",
484 rv, sdata->name);
485 goto out_err;
486 }
487 return;
488
489 out_err:
490 release_sdata(sdata);
491 }
492
493
494 /* Whenever the status of a sensor changes, the function is called
495 We display the information of the sensor if we find a new sensor */
496 static void
sensor_change(enum ipmi_update_e op,ipmi_entity_t * ent,ipmi_sensor_t * sensor,void * cb_data)497 sensor_change(enum ipmi_update_e op,
498 ipmi_entity_t *ent,
499 ipmi_sensor_t *sensor,
500 void *cb_data)
501 {
502 sdata_t *sdata;
503 int rv;
504
505 if (op == IPMI_ADDED) {
506 sdata = alloc_sdata(sensor);
507 if (!sdata) {
508 printf("Unable to allocate sensor name memory\n");
509 return;
510 }
511
512 printf("Sensor added: %s\n", sdata->name);
513
514 /* Get the current reading. */
515 if (ipmi_sensor_get_event_reading_type(sensor)
516 == IPMI_EVENT_READING_TYPE_THRESHOLD)
517 {
518 use_sdata(sdata);
519 rv = ipmi_sensor_get_reading(sensor, got_thresh_reading, sdata);
520 if (rv) {
521 printf("ipmi_reading_get returned error 0x%x for sensor %s\n",
522 rv, sdata->name);
523 release_sdata(sdata);
524 }
525 } else {
526 use_sdata(sdata);
527 rv = ipmi_sensor_get_states(sensor, got_discrete_states, sdata);
528 if (rv) {
529 printf("ipmi_states_get returned error 0x%x for sensor %s\n",
530 rv, sdata->name);
531 release_sdata(sdata);
532 }
533 }
534
535 /* Set up events. */
536 sdata->state_sup = ipmi_sensor_get_event_support(sensor);
537 switch (sdata->state_sup)
538 {
539 case IPMI_EVENT_SUPPORT_NONE:
540 case IPMI_EVENT_SUPPORT_GLOBAL_ENABLE:
541 /* No events to set up. */
542 printf("Sensor %s has no event support\n", sdata->name);
543 goto get_thresh;
544 }
545
546 use_sdata(sdata);
547 rv = ipmi_sensor_get_event_enables(sensor, got_events, sdata);
548 if (rv) {
549 printf("ipmi_sensor_events_enable_get returned error 0x%x"
550 " for sensor %s\n",
551 rv, sdata->name);
552 release_sdata(sdata);
553 }
554
555 get_thresh:
556 /* Handle the threshold settings. */
557
558 if (ipmi_sensor_get_event_reading_type(sensor)
559 != IPMI_EVENT_READING_TYPE_THRESHOLD)
560 /* Thresholds only for threshold sensors (duh) */
561 goto out;
562
563 sdata->thresh_sup = ipmi_sensor_get_threshold_access(sensor);
564
565 switch (sdata->thresh_sup)
566 {
567 case IPMI_THRESHOLD_ACCESS_SUPPORT_NONE:
568 printf("Sensor %s has no threshold support\n", sdata->name);
569 goto out;
570
571 case IPMI_THRESHOLD_ACCESS_SUPPORT_FIXED:
572 printf("Sensor %s has fixed threshold support\n", sdata->name);
573 goto out;
574 }
575
576 use_sdata(sdata);
577 rv = ipmi_sensor_get_thresholds(sensor, got_thresholds, sdata);
578 if (rv) {
579 printf("ipmi_thresholds_get returned error 0x%x"
580 " for sensor %s\n",
581 rv, sdata->name);
582 release_sdata(sdata);
583 }
584 } else if (op == IPMI_DELETED) {
585 sdata = find_sdata(sensor);
586 if (!sdata) {
587 char name[120];
588 ipmi_sensor_get_name(sensor, name, sizeof(name));
589
590 printf("sensor %s was deleted but not found in the sensor db\n",
591 name);
592 goto out;
593 }
594
595 printf("sensor %s was deleted\n", sdata->name);
596 release_sdata(sdata);
597 }
598
599 out:
600 return;
601 }
602
603 /* Whenever the status of an entity changes, the function is called
604 When a new entity is created, we search all sensors that belong
605 to the entity */
606 static void
entity_change(enum ipmi_update_e op,ipmi_domain_t * domain,ipmi_entity_t * entity,void * cb_data)607 entity_change(enum ipmi_update_e op,
608 ipmi_domain_t *domain,
609 ipmi_entity_t *entity,
610 void *cb_data)
611 {
612 int rv;
613 char name[50];
614
615 ipmi_entity_get_name(entity, name, sizeof(name));
616 if (op == IPMI_ADDED) {
617 printf("Entity added: %s\n", name);
618 /* Register callback so that when the status of a
619 sensor changes, sensor_change is called */
620 rv = ipmi_entity_add_sensor_update_handler(entity,
621 sensor_change,
622 NULL);
623 if (rv) {
624 printf("ipmi_entity_set_sensor_update_handler: 0x%x", rv);
625 exit(1);
626 }
627 }
628 }
629
630 /* After we have established connection to domain, this function get called
631 At this time, we can do whatever things we want to do. Herr we want to
632 search all entities in the system */
633 void
setup_done(ipmi_domain_t * domain,int err,unsigned int conn_num,unsigned int port_num,int still_connected,void * user_data)634 setup_done(ipmi_domain_t *domain,
635 int err,
636 unsigned int conn_num,
637 unsigned int port_num,
638 int still_connected,
639 void *user_data)
640 {
641 int rv;
642
643 /* Register a callback functin entity_change. When a new entities
644 is created, entity_change is called */
645 rv = ipmi_domain_add_entity_update_handler(domain, entity_change, domain);
646 if (rv) {
647 printf("ipmi_domain_add_entity_update_handler return error: %d\n", rv);
648 return;
649 }
650 }
651
652 static os_handler_t *os_hnd;
653
654 int
main(int argc,char * argv[])655 main(int argc, char *argv[])
656 {
657 int rv;
658 int curr_arg = 1;
659 ipmi_args_t *args;
660 ipmi_con_t *con;
661
662 progname = argv[0];
663
664 /* OS handler allocated first. */
665 os_hnd = ipmi_posix_setup_os_handler();
666 if (!os_hnd) {
667 printf("ipmi_smi_setup_con: Unable to allocate os handler\n");
668 exit(1);
669 }
670
671 /* Use the default log handler. */
672
673 /* Initialize the OpenIPMI library. */
674 ipmi_init(os_hnd);
675
676 rv = ipmi_parse_args2(&curr_arg, argc, argv, &args);
677 if (rv) {
678 fprintf(stderr, "Error parsing command arguments, argument %d: %s\n",
679 curr_arg, strerror(rv));
680 usage();
681 exit(1);
682 }
683
684 rv = ipmi_args_setup_con(args, os_hnd, NULL, &con);
685 if (rv) {
686 fprintf(stderr, "ipmi_ip_setup_con: %s", strerror(rv));
687 exit(1);
688 }
689
690 rv = ipmi_open_domain("", &con, 1, setup_done, NULL, NULL, NULL,
691 NULL, 0, NULL);
692 if (rv) {
693 fprintf(stderr, "ipmi_init_domain: %s\n", strerror(rv));
694 exit(1);
695 }
696
697 /* This is the main loop of the event-driven program.
698 Try <CTRL-C> to exit the program */
699 /* Let the selector code run the select loop. */
700 os_hnd->operation_loop(os_hnd);
701
702 /* Technically, we can't get here, but this is an example. */
703 os_hnd->free_os_handler(os_hnd);
704 return 0;
705 }
706